From: Richard Huang Date: Tue, 12 Sep 2023 09:32:17 +0000 (+0100) Subject: [NUI.Physics2D] Add binding for Chipmunk2D physics engine X-Git-Tag: accepted/tizen/unified/20231205.024657~134 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=42cea847d6e54f535577c0c37531cb04a66c8405;p=platform%2Fcore%2Fcsapi%2Ftizenfx.git [NUI.Physics2D] Add binding for Chipmunk2D physics engine --- diff --git a/src/Tizen.NUI.Physics2D/Properties/AssemblyInfo.cs b/src/Tizen.NUI.Physics2D/Properties/AssemblyInfo.cs new file mode 100755 index 0000000..3110dbc --- /dev/null +++ b/src/Tizen.NUI.Physics2D/Properties/AssemblyInfo.cs @@ -0,0 +1,4 @@ +using Tizen.NUI; + +// Xamarin.Forms.Loader.dll Xamarin.Forms.Xaml.XamlLoader.Load(object, string), kzu@microsoft.com +[assembly: XmlnsDefinition("http://tizen.org/Tizen.NUI/2018/XAML", "Tizen.NUI.Physics2D")] diff --git a/src/Tizen.NUI.Physics2D/Tizen.NUI.Physics2D.csproj b/src/Tizen.NUI.Physics2D/Tizen.NUI.Physics2D.csproj new file mode 100755 index 0000000..ab51d11 --- /dev/null +++ b/src/Tizen.NUI.Physics2D/Tizen.NUI.Physics2D.csproj @@ -0,0 +1,17 @@ + + + + net6.0 + $(NoWarn);CS0618;CA1054;CA1056 + + + + + + + + + + + + diff --git a/src/Tizen.NUI.Physics2D/Tizen.NUI.Physics2D.sln b/src/Tizen.NUI.Physics2D/Tizen.NUI.Physics2D.sln new file mode 100755 index 0000000..f72eb28 --- /dev/null +++ b/src/Tizen.NUI.Physics2D/Tizen.NUI.Physics2D.sln @@ -0,0 +1,79 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.31515.178 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tizen.NUI.Physics2D", "Tizen.NUI.Physics2D.csproj", "{F6CEE887-775A-4623-8BF8-DCA18C363D62}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tizen.NUI", "..\Tizen.NUI\Tizen.NUI.csproj", "{F9DAA9C3-593D-467E-B02C-FFF51F1BC8CD}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tizen.Applications.Common", "..\Tizen.Applications.Common\Tizen.Applications.Common.csproj", "{CE90CD24-82F7-45A3-96B2-2E3C97D25C30}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tizen.System.SystemSettings", "..\Tizen.System.SystemSettings\Tizen.System.SystemSettings.csproj", "{D726EEB8-6382-4BA3-BE0C-D9E61B5D8374}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tizen", "..\Tizen\Tizen.csproj", "{6D5FFD69-6DCC-4953-85E9-C23AC18B190E}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tizen.System.Information", "..\Tizen.System.Information\Tizen.System.Information.csproj", "{A951EAFE-D191-4F45-9AEF-7D97C382A747}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tizen.Log", "..\Tizen.Log\Tizen.Log.csproj", "{E1E30AEC-AD46-4E53-B9B1-780A68B59963}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tizen.Applications.ComponentBased", "..\Tizen.Applications.ComponentBased\Tizen.Applications.ComponentBased.csproj", "{70341AA2-1324-4215-9DB8-BFB13389D932}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tizen.Applications.ThemeManager", "..\Tizen.Applications.ThemeManager\Tizen.Applications.ThemeManager.csproj", "{F6A776BF-6743-4C1D-A8AF-F3E9F8CEFA0A}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tizen.Tracer", "..\Tizen.Tracer\Tizen.Tracer.csproj", "{6DABE78F-1816-4F2E-8966-F909173194C8}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {F6CEE887-775A-4623-8BF8-DCA18C363D62}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F6CEE887-775A-4623-8BF8-DCA18C363D62}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F6CEE887-775A-4623-8BF8-DCA18C363D62}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F6CEE887-775A-4623-8BF8-DCA18C363D62}.Release|Any CPU.Build.0 = Release|Any CPU + {F9DAA9C3-593D-467E-B02C-FFF51F1BC8CD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F9DAA9C3-593D-467E-B02C-FFF51F1BC8CD}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F9DAA9C3-593D-467E-B02C-FFF51F1BC8CD}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F9DAA9C3-593D-467E-B02C-FFF51F1BC8CD}.Release|Any CPU.Build.0 = Release|Any CPU + {CE90CD24-82F7-45A3-96B2-2E3C97D25C30}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {CE90CD24-82F7-45A3-96B2-2E3C97D25C30}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CE90CD24-82F7-45A3-96B2-2E3C97D25C30}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CE90CD24-82F7-45A3-96B2-2E3C97D25C30}.Release|Any CPU.Build.0 = Release|Any CPU + {D726EEB8-6382-4BA3-BE0C-D9E61B5D8374}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D726EEB8-6382-4BA3-BE0C-D9E61B5D8374}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D726EEB8-6382-4BA3-BE0C-D9E61B5D8374}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D726EEB8-6382-4BA3-BE0C-D9E61B5D8374}.Release|Any CPU.Build.0 = Release|Any CPU + {6D5FFD69-6DCC-4953-85E9-C23AC18B190E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6D5FFD69-6DCC-4953-85E9-C23AC18B190E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6D5FFD69-6DCC-4953-85E9-C23AC18B190E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6D5FFD69-6DCC-4953-85E9-C23AC18B190E}.Release|Any CPU.Build.0 = Release|Any CPU + {A951EAFE-D191-4F45-9AEF-7D97C382A747}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A951EAFE-D191-4F45-9AEF-7D97C382A747}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A951EAFE-D191-4F45-9AEF-7D97C382A747}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A951EAFE-D191-4F45-9AEF-7D97C382A747}.Release|Any CPU.Build.0 = Release|Any CPU + {E1E30AEC-AD46-4E53-B9B1-780A68B59963}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E1E30AEC-AD46-4E53-B9B1-780A68B59963}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E1E30AEC-AD46-4E53-B9B1-780A68B59963}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E1E30AEC-AD46-4E53-B9B1-780A68B59963}.Release|Any CPU.Build.0 = Release|Any CPU + {70341AA2-1324-4215-9DB8-BFB13389D932}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {70341AA2-1324-4215-9DB8-BFB13389D932}.Debug|Any CPU.Build.0 = Debug|Any CPU + {70341AA2-1324-4215-9DB8-BFB13389D932}.Release|Any CPU.ActiveCfg = Release|Any CPU + {70341AA2-1324-4215-9DB8-BFB13389D932}.Release|Any CPU.Build.0 = Release|Any CPU + {F6A776BF-6743-4C1D-A8AF-F3E9F8CEFA0A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F6A776BF-6743-4C1D-A8AF-F3E9F8CEFA0A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F6A776BF-6743-4C1D-A8AF-F3E9F8CEFA0A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F6A776BF-6743-4C1D-A8AF-F3E9F8CEFA0A}.Release|Any CPU.Build.0 = Release|Any CPU + {6DABE78F-1816-4F2E-8966-F909173194C8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6DABE78F-1816-4F2E-8966-F909173194C8}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6DABE78F-1816-4F2E-8966-F909173194C8}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6DABE78F-1816-4F2E-8966-F909173194C8}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {83C85CFB-3AB8-403A-9F6D-CC2783C6C559} + EndGlobalSection +EndGlobal diff --git a/src/Tizen.NUI.Physics2D/src/internal/chipmunk/DelegateExtensions.cs b/src/Tizen.NUI.Physics2D/src/internal/chipmunk/DelegateExtensions.cs new file mode 100644 index 0000000..dc2aed0 --- /dev/null +++ b/src/Tizen.NUI.Physics2D/src/internal/chipmunk/DelegateExtensions.cs @@ -0,0 +1,304 @@ +/* + * Copyright (c) 2023 Codefoco (codefoco@codefoco.com) + * + * 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. + */ + +using System; +using System.Runtime.InteropServices; + +namespace Tizen.NUI.Physics2D.Chipmunk +{ + /// + /// Create a ToFunctionPointer extension method for each delegate type. Unfortunately C# 7.0 + /// can't do something like that (you will need C# 7.3), thus we create one extension method for + /// each delegate public static IntPtr ToFunctionPointer T (this T d) where T : Delegate + /// + static internal class DelegateExtensions + { + public static IntPtr ToFunctionPointer(this BodyArbiterIteratorFunction d) + { + if (d == null) + { + return IntPtr.Zero; + } + + return Marshal.GetFunctionPointerForDelegate(d); + } + + public static IntPtr ToFunctionPointer(this BodyConstraintIteratorFunction d) + { + if (d == null) + { + return IntPtr.Zero; + } + + return Marshal.GetFunctionPointerForDelegate(d); + } + + public static IntPtr ToFunctionPointer(this BodyShapeIteratorFunction d) + { + if (d == null) + { + return IntPtr.Zero; + } + + return Marshal.GetFunctionPointerForDelegate(d); + } + + public static IntPtr ToFunctionPointer(this BodyVelocityFunction d) + { + if (d == null) + { + return IntPtr.Zero; + } + + return Marshal.GetFunctionPointerForDelegate(d); + } + + public static IntPtr ToFunctionPointer(this BodyPositionFunction d) + { + if (d == null) + { + return IntPtr.Zero; + } + + return Marshal.GetFunctionPointerForDelegate(d); + } + + public static IntPtr ToFunctionPointer(this CollisionBeginFunction d) + { + if (d == null) + { + return IntPtr.Zero; + } + + return Marshal.GetFunctionPointerForDelegate(d); + } + + + public static IntPtr ToFunctionPointer(this CollisionPreSolveFunction d) + { + if (d == null) + { + return IntPtr.Zero; + } + + return Marshal.GetFunctionPointerForDelegate(d); + } + + + public static IntPtr ToFunctionPointer(this CollisionPostSolveFunction d) + { + if (d == null) + { + return IntPtr.Zero; + } + + return Marshal.GetFunctionPointerForDelegate(d); + } + + + public static IntPtr ToFunctionPointer(this CollisionSeparateFunction d) + { + if (d == null) + { + return IntPtr.Zero; + } + + return Marshal.GetFunctionPointerForDelegate(d); + } + + + public static IntPtr ToFunctionPointer(this PostStepFunction d) + { + if (d == null) + { + return IntPtr.Zero; + } + + return Marshal.GetFunctionPointerForDelegate(d); + } + + + public static IntPtr ToFunctionPointer(this SpaceSegmentQueryFunction d) + { + if (d == null) + { + return IntPtr.Zero; + } + + return Marshal.GetFunctionPointerForDelegate(d); + } + + public static IntPtr ToFunctionPointer(this SpacePointQueryFunction d) + { + if (d == null) + { + return IntPtr.Zero; + } + + return Marshal.GetFunctionPointerForDelegate(d); + } + + public static IntPtr ToFunctionPointer(this SpaceBBQueryFunction d) + { + if (d == null) + { + return IntPtr.Zero; + } + + return Marshal.GetFunctionPointerForDelegate(d); + } + + + public static IntPtr ToFunctionPointer(this SpaceObjectIteratorFunction d) + { + if (d == null) + { + return IntPtr.Zero; + } + + return Marshal.GetFunctionPointerForDelegate(d); + } + + + public static IntPtr ToFunctionPointer(this SpaceDebugDrawCircleImpl d) + { + if (d == null) + { + return IntPtr.Zero; + } + + return Marshal.GetFunctionPointerForDelegate(d); + } + + + public static IntPtr ToFunctionPointer(this SpaceDebugDrawSegmentImpl d) + { + if (d == null) + { + return IntPtr.Zero; + } + + return Marshal.GetFunctionPointerForDelegate(d); + } + + public static IntPtr ToFunctionPointer(this SpaceDebugDrawFatSegmentImpl d) + { + if (d == null) + { + return IntPtr.Zero; + } + + return Marshal.GetFunctionPointerForDelegate(d); + } + + public static IntPtr ToFunctionPointer(this SpaceDebugDrawPolygonImpl d) + { + if (d == null) + { + return IntPtr.Zero; + } + + return Marshal.GetFunctionPointerForDelegate(d); + } + + public static IntPtr ToFunctionPointer(this SpaceDebugDrawDotImpl d) + { + if (d == null) + { + return IntPtr.Zero; + } + + return Marshal.GetFunctionPointerForDelegate(d); + } + + public static IntPtr ToFunctionPointer(this SpaceDebugDrawColorForShapeImpl d) + { + if (d == null) + { + return IntPtr.Zero; + } + + return Marshal.GetFunctionPointerForDelegate(d); + } + + + public static IntPtr ToFunctionPointer(this ConstraintSolveFunction d) + { + if (d == null) + { + return IntPtr.Zero; + } + + return Marshal.GetFunctionPointerForDelegate(d); + } + + public static IntPtr ToFunctionPointer(this DampedSpringForceFunction d) + { + if (d == null) + { + return IntPtr.Zero; + } + + return Marshal.GetFunctionPointerForDelegate(d); + } + + public static IntPtr ToFunctionPointer(this DampedRotarySpringTorqueFunction d) + { + if (d == null) + { + return IntPtr.Zero; + } + + return Marshal.GetFunctionPointerForDelegate(d); + } + + public static IntPtr ToFunctionPointer(this SpaceShapeQueryFunction d) + { + if (d == null) + { + return IntPtr.Zero; + } + + return Marshal.GetFunctionPointerForDelegate(d); + } + + public static IntPtr ToFunctionPointer(this MarchSegmentFunction d) + { + if (d == null) + { + return IntPtr.Zero; + } + + return Marshal.GetFunctionPointerForDelegate(d); + } + + public static IntPtr ToFunctionPointer(this MarchSampleFunction d) + { + if (d == null) + { + return IntPtr.Zero; + } + + return Marshal.GetFunctionPointerForDelegate(d); + } + } +} diff --git a/src/Tizen.NUI.Physics2D/src/internal/chipmunk/Delegates.cs b/src/Tizen.NUI.Physics2D/src/internal/chipmunk/Delegates.cs new file mode 100644 index 0000000..8c2d219 --- /dev/null +++ b/src/Tizen.NUI.Physics2D/src/internal/chipmunk/Delegates.cs @@ -0,0 +1,304 @@ +/* + * Copyright (c) 2023 Codefoco (codefoco@codefoco.com) + * + * 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. + */ + +using System.Runtime.InteropServices; +using System.Security; +using cpArbiter = System.IntPtr; +using cpBody = System.IntPtr; +using cpBool = System.Byte; +using cpConstraint = System.IntPtr; +using cpContactPointSetPointer = System.IntPtr; +using cpHandle = System.IntPtr; +using cpShape = System.IntPtr; +using cpSpace = System.IntPtr; +using cpVertPointer = System.IntPtr; +using voidptr_t = System.IntPtr; + +#if __IOS__ || __TVOS__ || __WATCHOS__ || __MACCATALYST__ +using ObjCRuntime; +#endif + +namespace Tizen.NUI.Physics2D.Chipmunk +{ + /// + /// Delegate method to iterate over arbiters. + /// + [SuppressUnmanagedCodeSecurity] + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] +#if __IOS__ || __TVOS__ || __WATCHOS__ || __MACCATALYST__ + [MonoNativeFunctionWrapper] +#endif + internal delegate void BodyArbiterIteratorFunction(cpBody body, cpArbiter arbiter, voidptr_t data); + + [SuppressUnmanagedCodeSecurity] + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] +#if __IOS__ || __TVOS__ || __WATCHOS__ || __MACCATALYST__ + [MonoNativeFunctionWrapper] +#endif + internal delegate void BodyVelocityFunction(cpBody body, Vect gravity, double damping, double dt); + + /// + /// Rigid body position update function type. + /// + [SuppressUnmanagedCodeSecurity] + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] +#if __IOS__ || __TVOS__ || __WATCHOS__ || __MACCATALYST__ + [MonoNativeFunctionWrapper] +#endif + internal delegate void BodyPositionFunction(cpBody body, double dt); + + /// + /// Delegate method to iterate over constraints. + /// + [SuppressUnmanagedCodeSecurity] + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] +#if __IOS__ || __TVOS__ || __WATCHOS__ || __MACCATALYST__ + [MonoNativeFunctionWrapper] +#endif + internal delegate void BodyConstraintIteratorFunction(cpBody body, cpConstraint constraint, voidptr_t data); + + /// + /// Delegate method to iterate over shapes. + /// + [SuppressUnmanagedCodeSecurity] + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] +#if __IOS__ || __TVOS__ || __WATCHOS__ || __MACCATALYST__ + [MonoNativeFunctionWrapper] +#endif + internal delegate void BodyShapeIteratorFunction(cpBody body, cpShape shape, voidptr_t data); + + /// + /// Collision begin event function callback type. Returning false from a begin callback causes + /// the collision to be ignored until the the separate callback is called when the objects stop + /// colliding. + /// + [SuppressUnmanagedCodeSecurity] + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] +#if __IOS__ || __TVOS__ || __WATCHOS__ || __MACCATALYST__ + [MonoNativeFunctionWrapper] +#endif + internal delegate void CollisionBeginFunction(cpArbiter arbiter, cpSpace space, voidptr_t userData); + + /// + /// Collision pre-solve event function callback type. Returning false from a pre-step callback + /// causes the collision to be ignored until the next step. + /// + [SuppressUnmanagedCodeSecurity] + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] +#if __IOS__ || __TVOS__ || __WATCHOS__ || __MACCATALYST__ + [MonoNativeFunctionWrapper] +#endif + internal delegate cpBool CollisionPreSolveFunction(cpArbiter arbiter, cpSpace space, voidptr_t userData); + + /// + /// Collision Post-Solve . + /// + [SuppressUnmanagedCodeSecurity] + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] +#if __IOS__ || __TVOS__ || __WATCHOS__ || __MACCATALYST__ + [MonoNativeFunctionWrapper] +#endif + internal delegate void CollisionPostSolveFunction(cpArbiter arbiter, cpSpace space, voidptr_t userData); + + /// + /// Collision separate event function callback type. + /// + [SuppressUnmanagedCodeSecurity] + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] +#if __IOS__ || __TVOS__ || __WATCHOS__ || __MACCATALYST__ + [MonoNativeFunctionWrapper] +#endif + internal delegate void CollisionSeparateFunction(cpArbiter arbiter, cpSpace space, voidptr_t userData); + + /// + /// Post Step callback function type. + /// + [SuppressUnmanagedCodeSecurity] + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] +#if __IOS__ || __TVOS__ || __WATCHOS__ || __MACCATALYST__ + [MonoNativeFunctionWrapper] +#endif + internal delegate void PostStepFunction(cpSpace space, voidptr_t key, voidptr_t data); + + /// + /// Nearest point query callback function type. + /// + [SuppressUnmanagedCodeSecurity] + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] +#if __IOS__ || __TVOS__ || __WATCHOS__ || __MACCATALYST__ + [MonoNativeFunctionWrapper] +#endif + internal delegate void SpacePointQueryFunction(cpShape shape, Vect point, double distance, Vect gradient, voidptr_t data); + + /// + /// Segment query callback function type. + /// + [SuppressUnmanagedCodeSecurity] + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] +#if __IOS__ || __TVOS__ || __WATCHOS__ || __MACCATALYST__ + [MonoNativeFunctionWrapper] +#endif + internal delegate void SpaceSegmentQueryFunction(cpShape shape, Vect point, Vect normal, double alpha, voidptr_t data); + + /// + /// Rectangle Query callback function type. + /// + [SuppressUnmanagedCodeSecurity] + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] +#if __IOS__ || __TVOS__ || __WATCHOS__ || __MACCATALYST__ + [MonoNativeFunctionWrapper] +#endif + internal delegate void SpaceBBQueryFunction(cpShape shape, voidptr_t data); + + /// + /// Space/object iterator callback function type. + /// + [SuppressUnmanagedCodeSecurity] + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] +#if __IOS__ || __TVOS__ || __WATCHOS__ || __MACCATALYST__ + [MonoNativeFunctionWrapper] +#endif + internal delegate void SpaceObjectIteratorFunction(cpHandle handle, voidptr_t data); + + /// + /// Callback type for a function that draws a filled, stroked circle. + /// + [SuppressUnmanagedCodeSecurity] + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] +#if __IOS__ || __TVOS__ || __WATCHOS__ || __MACCATALYST__ + [MonoNativeFunctionWrapper] +#endif + internal delegate void SpaceDebugDrawCircleImpl(Vect pos, double angle, double radius, DebugColor outlineColor, DebugColor fillColor, voidptr_t data); + + /// + /// Callback type for a function that draws a line segment. + /// + [SuppressUnmanagedCodeSecurity] + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] +#if __IOS__ || __TVOS__ || __WATCHOS__ || __MACCATALYST__ + [MonoNativeFunctionWrapper] +#endif + internal delegate void SpaceDebugDrawSegmentImpl(Vect a, Vect b, DebugColor color, voidptr_t data); + + /// + /// Callback type for a function that draws a thick line segment. + /// + [SuppressUnmanagedCodeSecurity] + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] +#if __IOS__ || __TVOS__ || __WATCHOS__ || __MACCATALYST__ + [MonoNativeFunctionWrapper] +#endif + internal delegate void SpaceDebugDrawFatSegmentImpl(Vect a, Vect b, double radius, DebugColor outlineColor, DebugColor fillColor, voidptr_t data); + + /// + /// Callback type for a function that draws a convex polygon. + /// + [SuppressUnmanagedCodeSecurity] + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] +#if __IOS__ || __TVOS__ || __WATCHOS__ || __MACCATALYST__ + [MonoNativeFunctionWrapper] +#endif + internal delegate void SpaceDebugDrawPolygonImpl(int count, cpVertPointer verts, double radius, DebugColor outlineColor, DebugColor fillColor, voidptr_t data); + + /// + /// Callback type for a function that draws a dot. + /// + [SuppressUnmanagedCodeSecurity] + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] +#if __IOS__ || __TVOS__ || __WATCHOS__ || __MACCATALYST__ + [MonoNativeFunctionWrapper] +#endif + internal delegate void SpaceDebugDrawDotImpl(double size, Vect pos, DebugColor color, voidptr_t data); + + /// + /// Callback type for a function that returns a color for a given shape. This gives you an + /// opportunity to color shapes based on how they are used in your engine. + /// + [SuppressUnmanagedCodeSecurity] + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] +#if __IOS__ || __TVOS__ || __WATCHOS__ || __MACCATALYST__ + [MonoNativeFunctionWrapper] +#endif + internal delegate DebugColor SpaceDebugDrawColorForShapeImpl(cpShape shape, voidptr_t data); + + /// + /// Callback function type that gets called after/before solving a joint. + /// + [SuppressUnmanagedCodeSecurity] + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] +#if __IOS__ || __TVOS__ || __WATCHOS__ || __MACCATALYST__ + [MonoNativeFunctionWrapper] +#endif + internal delegate void ConstraintSolveFunction(cpConstraint constraint, cpSpace space); + + /// + /// Function type used for damped spring force callbacks. + /// + [SuppressUnmanagedCodeSecurity] + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] +#if __IOS__ || __TVOS__ || __WATCHOS__ || __MACCATALYST__ + [MonoNativeFunctionWrapper] +#endif + internal delegate double DampedSpringForceFunction(cpConstraint spring, double dist); + + /// + /// Function type used for damped rotary spring force callbacks + /// + [SuppressUnmanagedCodeSecurity] + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] +#if __IOS__ || __TVOS__ || __WATCHOS__ || __MACCATALYST__ + [MonoNativeFunctionWrapper] +#endif + internal delegate double DampedRotarySpringTorqueFunction(cpConstraint spring, double relativeAngle); + + /// + /// Shape query callback function type. + /// + [SuppressUnmanagedCodeSecurity] + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] +#if __IOS__ || __TVOS__ || __WATCHOS__ || __MACCATALYST__ + [MonoNativeFunctionWrapper] +#endif + internal delegate void SpaceShapeQueryFunction(cpShape shape, cpContactPointSetPointer points, voidptr_t data); + + /// + /// Function type used as a callback from the marching squares algorithm to output a line + /// segment. It passes you the two endpoints and your context pointer. + /// + [SuppressUnmanagedCodeSecurity] + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] +#if __IOS__ || __TVOS__ || __WATCHOS__ || __MACCATALYST__ + [MonoNativeFunctionWrapper] +#endif + internal delegate void MarchSegmentFunction(Vect v0, Vect v1, voidptr_t data); + + /// + /// Function type used as a callback from the marching squares algorithm to sample an image function. + /// It passes you the point to sample and your context pointer, and you return the density. + /// + [SuppressUnmanagedCodeSecurity] + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] +#if __IOS__ || __TVOS__ || __WATCHOS__ || __MACCATALYST__ + [MonoNativeFunctionWrapper] +#endif + internal delegate double MarchSampleFunction(Vect point, voidptr_t data); +} diff --git a/src/Tizen.NUI.Physics2D/src/internal/chipmunk/NativeInterop.cs b/src/Tizen.NUI.Physics2D/src/internal/chipmunk/NativeInterop.cs new file mode 100644 index 0000000..5859c0b --- /dev/null +++ b/src/Tizen.NUI.Physics2D/src/internal/chipmunk/NativeInterop.cs @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2023 Codefoco (codefoco@codefoco.com) + * + * 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. + */ + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Runtime.InteropServices; + +namespace Tizen.NUI.Physics2D.Chipmunk +{ + internal static class NativeInterop + { + public static IntPtr RegisterHandle(object obj) + { + var gcHandle = GCHandle.Alloc(obj); + return GCHandle.ToIntPtr(gcHandle); + } + + public static T FromIntPtr(IntPtr pointer) + { + Debug.Assert(pointer != IntPtr.Zero, "IntPtr parameter should never be Zero"); + + var handle = GCHandle.FromIntPtr(pointer); + + Debug.Assert(handle.IsAllocated, "GCHandle not allocated."); + Debug.Assert(handle.Target is T, "Target is not of type T."); + + return (T)handle.Target; + } + + public static void ReleaseHandle(IntPtr pointer) + { + Debug.Assert(pointer != IntPtr.Zero, "IntPtr parameter should never be Zero"); + + var handle = GCHandle.FromIntPtr(pointer); + + Debug.Assert(handle.IsAllocated, "GCHandle not allocated."); + + handle.Free(); + } + + public static T FromIntPtrAndFree(IntPtr pointer) + { + Debug.Assert(pointer != IntPtr.Zero, "IntPtr parameter should never be Zero"); + + var handle = GCHandle.FromIntPtr(pointer); + + Debug.Assert(handle.IsAllocated, "GCHandle not allocated."); + Debug.Assert(handle.Target is T, "Target is not of type T."); + T obj = (T)handle.Target; + + handle.Free(); + + return obj; + } + + public static int SizeOf() + { + return Marshal.SizeOf(); + } + + public static IntPtr AllocStructure() + { + int size = SizeOf(); + return Marshal.AllocHGlobal(size); + } + + public static void FreeStructure(IntPtr ptr) + { + Marshal.FreeHGlobal(ptr); + } + + public static T PtrToStructure(IntPtr intPtr) + { + return Marshal.PtrToStructure(intPtr); + } + + public static T[] PtrToStructureArray(IntPtr intPtr, int count) + { + var items = new T[count]; + var size = SizeOf(); + + for (var i = 0; i < count; i++) + { + var newPtr = new IntPtr(intPtr.ToInt64() + (i * size)); + items[i] = PtrToStructure(newPtr); + } + + return items; + } + + internal static IntPtr StructureArrayToPtr(IReadOnlyList items) + { + var size = SizeOf(); + var memory = Marshal.AllocHGlobal(size * items.Count); + + for (var i = 0; i < items.Count; i++) + { + var ptr = new IntPtr(memory.ToInt64() + (i * size)); + Marshal.StructureToPtr(items[i], ptr, true); + } + + return memory; + } + } +} diff --git a/src/Tizen.NUI.Physics2D/src/internal/chipmunk/NativeMethods.cs b/src/Tizen.NUI.Physics2D/src/internal/chipmunk/NativeMethods.cs new file mode 100644 index 0000000..305d403 --- /dev/null +++ b/src/Tizen.NUI.Physics2D/src/internal/chipmunk/NativeMethods.cs @@ -0,0 +1,1228 @@ +/* + * Copyright (c) 2023 Codefoco (codefoco@codefoco.com) + * + * 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. + */ + +// ReSharper disable IdentifierTypo +using System; +using System.Runtime.InteropServices; +using System.Security; +using cpArbiter = System.IntPtr; +using cpBitmask = System.UInt32; +using cpBody = System.IntPtr; +using cpBodyArbiterIteratorFunc = System.IntPtr; +using cpBodyConstraintIteratorFunc = System.IntPtr; +using cpBodyPositionFunc = System.IntPtr; +using cpBodyShapeIteratorFunc = System.IntPtr; +using cpBodyType = System.Int32; +using cpBodyVelocityFunc = System.IntPtr; +using cpBool = System.Byte; +using cpCollisionHandlerPointer = System.IntPtr; +using cpCollisionType = System.UIntPtr; +using cpConstraint = System.IntPtr; +using cpConstraintPostSolveFunc = System.IntPtr; +using cpConstraintPreSolveFunc = System.IntPtr; +using cpDampedRotarySpringTorqueFunc = System.IntPtr; +using cpDampedSpringForceFunc = System.IntPtr; +using cpDataPointer = System.IntPtr; +using cpFloat = System.Double; +using cpGroup = System.UIntPtr; +using cpMarchSampleFunc = System.IntPtr; +using cpMarchSegmentFunc = System.IntPtr; +using cpPolyline = System.IntPtr; +using cpPolylineSet = System.IntPtr; +using cpPostStepFunc = System.IntPtr; +using cpShape = System.IntPtr; +using cpSpace = System.IntPtr; +using cpSpaceBBQueryFunc = System.IntPtr; +using cpSpaceBodyIteratorFunc = System.IntPtr; +using cpSpaceConstraintIteratorFunc = System.IntPtr; +using cpSpaceDebugDrawOptionsPointer = System.IntPtr; +using cpSpaceHash = System.IntPtr; +using cpSpacePointQueryFunc = System.IntPtr; +using cpSpaceSegmentQueryFunc = System.IntPtr; +using cpSpaceShapeIteratorFunc = System.IntPtr; +using cpSpaceShapeQueryFunc = System.IntPtr; +using cpSpatialIndex = System.IntPtr; +using cpSpatialIndexBBFunc = System.IntPtr; +using cpSpatialIndexQueryFunc = System.IntPtr; +using cpSweep1D = System.IntPtr; +using cpTimestamp = System.UInt32; +using cpVectPointer = System.IntPtr; +using VoidPointer = System.IntPtr; + +namespace Tizen.NUI.Physics2D.Chipmunk +{ + [SuppressUnmanagedCodeSecurity] + internal static class NativeMethods + { + +#pragma warning disable CA1823 // Unused field 'ChipmunkLibraryName' + +#if __MACOS__ + private const string ChipmunkLibraryName = "libchipmunk.dylib"; +#else + private const string ChipmunkLibraryName = "libchipmunk.so"; +#endif + +#pragma warning restore CA1823 // Unused field 'ChipmunkLibraryName' + +#pragma warning disable IDE1006 // Naming Styles + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpArbiterCallWildcardBeginA(cpArbiter arb, cpSpace space); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpArbiterCallWildcardBeginB(cpArbiter arb, cpSpace space); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpArbiterCallWildcardPostSolveA(cpArbiter arb, cpSpace space); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpArbiterCallWildcardPostSolveB(cpArbiter arb, cpSpace space); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpBool cpArbiterCallWildcardPreSolveA(cpArbiter arb, cpSpace space); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpBool cpArbiterCallWildcardPreSolveB(cpArbiter arb, cpSpace space); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpArbiterCallWildcardSeparateA(cpArbiter arb, cpSpace space); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpArbiterCallWildcardSeparateB(cpArbiter arb, cpSpace space); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpArbiterGetBodies(cpArbiter arb, out cpBody a, out cpBody b); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpContactPointSet cpArbiterGetContactPointSet(cpArbiter arb); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern int cpArbiterGetCount(cpArbiter arb); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpFloat cpArbiterGetDepth(cpArbiter arb, int i); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpFloat cpArbiterGetFriction(cpArbiter arb); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern Vect cpArbiterGetNormal(cpArbiter arb); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern Vect cpArbiterGetPointA(cpArbiter arb, int i); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern Vect cpArbiterGetPointB(cpArbiter arb, int i); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpFloat cpArbiterGetRestitution(cpArbiter arb); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpArbiterGetShapes(cpArbiter arb, out cpShape a, out cpShape b); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern Vect cpArbiterGetSurfaceVelocity(cpArbiter arb); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpDataPointer cpArbiterGetUserData(cpArbiter arb); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpBool cpArbiterIgnore(cpArbiter arb); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpBool cpArbiterIsFirstContact(cpArbiter arb); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpBool cpArbiterIsRemoval(cpArbiter arb); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpArbiterSetContactPointSet(cpArbiter arb, ref cpContactPointSet set); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpArbiterSetFriction(cpArbiter arb, cpFloat friction); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpArbiterSetRestitution(cpArbiter arb, cpFloat restitution); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpArbiterSetSurfaceVelocity(cpArbiter arb, Vect vr); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpArbiterSetUserData(cpArbiter arb, cpDataPointer userData); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern Vect cpArbiterTotalImpulse(cpArbiter arb); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpFloat cpArbiterTotalKE(cpArbiter arb); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpFloat cpAreaForCircle(cpFloat r1, cpFloat r2); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpFloat cpAreaForPoly(int count, cpVectPointer verts, cpFloat radius); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpFloat cpAreaForSegment(Vect a, Vect b, cpFloat radius); + + //[DllImport (ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + //internal static extern cpBBTree cpBBTreeAlloc(); + + //[DllImport (ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + //internal static extern cpSpatialIndex cpBBTreeInit(cpBBTree tree, cpSpatialIndexBBFunc bbfunc, cpSpatialIndex staticIndex); + + //[DllImport (ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + //internal static extern cpSpatialIndex cpBBTreeNew(cpSpatialIndexBBFunc bbfunc, cpSpatialIndex staticIndex); + + //[DllImport (ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + //internal static extern void cpBBTreeOptimize(cpSpatialIndex index); + + //[DllImport (ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + //internal static extern void cpBBTreeSetVelocityFunc(cpSpatialIndex index, cpBBTreeVelocityFunc func); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpBodyActivate(cpBody body); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpBodyActivateStatic(cpBody body, cpShape filter); + + //[DllImport (ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + //internal static extern cpBody cpBodyAlloc(); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpBodyApplyForceAtLocalPoint(cpBody body, Vect force, Vect point); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpBodyApplyForceAtWorldPoint(cpBody body, Vect force, Vect point); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpBodyApplyTorque(cpBody body, cpFloat torque); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpBodyApplyAngularImpulse(cpBody body, cpFloat impulse); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpBodyApplyImpulseAtLocalPoint(cpBody body, Vect impulse, Vect point); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpBodyApplyImpulseAtWorldPoint(cpBody body, Vect impulse, Vect point); + + //[DllImport (ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + //internal static extern void cpBodyDestroy(cpBody body); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpBool cpBodyContactWith(cpBody bodyA, cpBody bodyB); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpBodyEachArbiter(cpBody body, cpBodyArbiterIteratorFunc func, VoidPointer data); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpBodyEachConstraint(cpBody body, cpBodyConstraintIteratorFunc func, VoidPointer data); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpBodyEachShape(cpBody body, cpBodyShapeIteratorFunc func, VoidPointer data); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpBodyFree(cpBody body); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpFloat cpBodyGetAngle(cpBody body); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpFloat cpBodyGetAngularVelocity(cpBody body); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern Vect cpBodyGetCenterOfGravity(cpBody body); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern int cpBodyGetContactedBodiesCount(cpBody body); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpBodyGetUserDataContactedBodies(cpBody body, IntPtr userDataArray); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpBodyPositionFunc cpBodyGetDefaultPositionUpdateFunc(); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpBodyVelocityFunc cpBodyGetDefaultVelocityUpdateFunc(); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern Vect cpBodyGetForce(cpBody body); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpFloat cpBodyGetMass(cpBody body); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpFloat cpBodyGetMoment(cpBody body); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern Vect cpBodyGetPosition(cpBody body); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern Vect cpBodyGetRotation(cpBody body); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpSpace cpBodyGetSpace(cpBody body); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpBodyGetTransform(cpBody body, out Vect pos, out cpFloat angle); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpFloat cpBodyGetTorque(cpBody body); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpBodyType cpBodyGetType(cpBody body); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpDataPointer cpBodyGetUserData(cpBody body); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern Vect cpBodyGetVelocity(cpBody body); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern Vect cpBodyGetVelocityAtLocalPoint(cpBody body, Vect point); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern Vect cpBodyGetVelocityAtWorldPoint(cpBody body, Vect point); + + //[DllImport (ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + //internal static extern cpBody cpBodyInit(cpBody body, cpFloat mass, cpFloat moment); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpBool cpBodyIsSleeping(cpBody body); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpFloat cpBodyKineticEnergy(cpBody body); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern Vect cpBodyLocalToWorld(cpBody body, Vect point); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpBody cpBodyNew(cpFloat mass, cpFloat moment); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpBody cpBodyNewKinematic(); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpBody cpBodyNewStatic(); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpBodySetAngle(cpBody body, cpFloat a); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpBodySetAngularVelocity(cpBody body, cpFloat angularVelocity); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpBodySetCenterOfGravity(cpBody body, Vect cog); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpBodySetForce(cpBody body, Vect force); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpBodySetMass(cpBody body, cpFloat m); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpBodySetMoment(cpBody body, cpFloat i); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpBodySetPosition(cpBody body, Vect pos); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpBodySetPositionUpdateFunc(cpBody body, cpBodyPositionFunc positionFunc); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpBodySetTransform(cpBody body, Vect pos, cpFloat angle); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpBodySetTorque(cpBody body, cpFloat torque); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpBodySetType(cpBody body, cpBodyType type); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpBodySetUserData(cpBody body, cpDataPointer userData); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpBodySetVelocity(cpBody body, Vect velocity); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpBodySetVelocityUpdateFunc(cpBody body, cpBodyVelocityFunc velocityFunc); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpBodySleep(cpBody body); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpBodySleepWithGroup(cpBody body, cpBody group); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpBodyUpdatePosition(cpBody body, cpFloat dt); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpBodyUpdateVelocity(cpBody body, Vect gravity, cpFloat damping, cpFloat dt); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern Vect cpBodyWorldToLocal(cpBody body, Vect point); + + //[DllImport (ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + //internal static extern cpPolyShape cpBoxShapeInit(cpPolyShape poly, cpBody body, cpFloat width, cpFloat height, cpFloat radius); + + //[DllImport (ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + //internal static extern cpPolyShape cpBoxShapeInit2(cpPolyShape poly, cpBody body, BoundingBox box, cpFloat radius); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpShape cpBoxShapeNew(cpBody body, cpFloat width, cpFloat height, cpFloat radius); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpShape cpBoxShapeNew2(cpBody body, BoundingBox box, cpFloat radius); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern Vect cpCentroidForPoly(int count, cpVectPointer verts); + + //[DllImport (ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + //internal static extern cpCircleShape cpCircleShapeAlloc(); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern Vect cpCircleShapeGetOffset(cpShape shape); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpFloat cpCircleShapeGetRadius(cpShape shape); + + //[DllImport (ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + //internal static extern cpCircleShape cpCircleShapeInit(cpCircleShape circle, cpBody body, cpFloat radius, Vect offset); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpShape cpCircleShapeNew(cpBody body, cpFloat radius, Vect offset); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpCircleShapeSetOffset(cpShape shape, Vect offset); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpCircleShapeSetRadius(cpShape shape, cpFloat radius); + + //[DllImport (ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + //internal static extern void cpConstraintDestroy(cpConstraint constraint); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpConstraintFree(cpConstraint constraint); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpBody cpConstraintGetBodyA(cpConstraint constraint); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpBody cpConstraintGetBodyB(cpConstraint constraint); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpBool cpConstraintGetCollideBodies(cpConstraint constraint); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpFloat cpConstraintGetErrorBias(cpConstraint constraint); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpFloat cpConstraintGetImpulse(cpConstraint constraint); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpFloat cpConstraintGetMaxBias(cpConstraint constraint); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpFloat cpConstraintGetMaxForce(cpConstraint constraint); + + //[DllImport (ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + //internal static extern cpConstraintPostSolveFunc cpConstraintGetPostSolveFunc(cpConstraint constraint); + + //[DllImport (ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + //internal static extern cpConstraintPreSolveFunc cpConstraintGetPreSolveFunc(cpConstraint constraint); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpSpace cpConstraintGetSpace(cpConstraint constraint); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpDataPointer cpConstraintGetUserData(cpConstraint constraint); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpBool cpConstraintIsDampedRotarySpring(cpConstraint constraint); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpBool cpConstraintIsDampedSpring(cpConstraint constraint); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpBool cpConstraintIsGearJoint(cpConstraint constraint); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpBool cpConstraintIsGrooveJoint(cpConstraint constraint); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpBool cpConstraintIsPinJoint(cpConstraint constraint); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpBool cpConstraintIsPivotJoint(cpConstraint constraint); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpBool cpConstraintIsRatchetJoint(cpConstraint constraint); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpBool cpConstraintIsRotaryLimitJoint(cpConstraint constraint); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpBool cpConstraintIsSimpleMotor(cpConstraint constraint); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpBool cpConstraintIsSlideJoint(cpConstraint constraint); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpConstraintSetCollideBodies(cpConstraint constraint, cpBool collideBodies); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpConstraintSetErrorBias(cpConstraint constraint, cpFloat errorBias); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpConstraintSetMaxBias(cpConstraint constraint, cpFloat maxBias); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpConstraintSetMaxForce(cpConstraint constraint, cpFloat maxForce); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpConstraintSetPostSolveFunc(cpConstraint constraint, cpConstraintPostSolveFunc postSolveFunc); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpConstraintSetPreSolveFunc(cpConstraint constraint, cpConstraintPreSolveFunc preSolveFunc); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpConstraintSetUserData(cpConstraint constraint, cpDataPointer userData); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern int cpConvexHull(int count, cpVectPointer verts, cpVectPointer result, IntPtr first, cpFloat tol); + + //[DllImport (ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + //internal static extern cpDampedRotarySpring cpDampedRotarySpringAlloc(); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpFloat cpDampedRotarySpringGetDamping(cpConstraint constraint); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpFloat cpDampedRotarySpringGetRestAngle(cpConstraint constraint); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpDampedRotarySpringTorqueFunc cpDampedRotarySpringGetSpringTorqueFunc(cpConstraint constraint); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpFloat cpDampedRotarySpringGetStiffness(cpConstraint constraint); + + //[DllImport (ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + //internal static extern cpDampedRotarySpring cpDampedRotarySpringInit(cpDampedRotarySpring joint, cpBody a, cpBody b, cpFloat restAngle, cpFloat stiffness, cpFloat damping); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpConstraint cpDampedRotarySpringNew(cpBody a, cpBody b, cpFloat restAngle, cpFloat stiffness, cpFloat damping); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpDampedRotarySpringSetDamping(cpConstraint constraint, cpFloat damping); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpDampedRotarySpringSetRestAngle(cpConstraint constraint, cpFloat restAngle); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpDampedRotarySpringSetSpringTorqueFunc(cpConstraint constraint, cpDampedRotarySpringTorqueFunc springTorqueFunc); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpDampedRotarySpringSetStiffness(cpConstraint constraint, cpFloat stiffness); + + //[DllImport (ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + //internal static extern cpDampedSpring cpDampedSpringAlloc(); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern Vect cpDampedSpringGetAnchorA(cpConstraint constraint); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern Vect cpDampedSpringGetAnchorB(cpConstraint constraint); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpFloat cpDampedSpringGetDamping(cpConstraint constraint); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpFloat cpDampedSpringGetRestLength(cpConstraint constraint); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpDampedSpringForceFunc cpDampedSpringGetSpringForceFunc(cpConstraint constraint); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpFloat cpDampedSpringGetStiffness(cpConstraint constraint); + + //[DllImport (ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + //internal static extern cpDampedSpring cpDampedSpringInit(cpDampedSpring joint, cpBody a, cpBody b, Vect anchorA, Vect anchorB, cpFloat restLength, cpFloat stiffness, cpFloat damping); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpConstraint cpDampedSpringNew(cpBody a, cpBody b, Vect anchorA, Vect anchorB, cpFloat restLength, cpFloat stiffness, cpFloat damping); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpDampedSpringSetAnchorA(cpConstraint constraint, Vect anchorA); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpDampedSpringSetAnchorB(cpConstraint constraint, Vect anchorB); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpDampedSpringSetDamping(cpConstraint constraint, cpFloat damping); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpDampedSpringSetRestLength(cpConstraint constraint, cpFloat restLength); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpDampedSpringSetSpringForceFunc(cpConstraint constraint, cpDampedSpringForceFunc springForceFunc); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpDampedSpringSetStiffness(cpConstraint constraint, cpFloat stiffness); + + //[DllImport (ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + //internal static extern cpGearJoint cpGearJointAlloc(); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpFloat cpGearJointGetPhase(cpConstraint constraint); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpFloat cpGearJointGetRatio(cpConstraint constraint); + + //[DllImport (ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + //internal static extern cpGearJoint cpGearJointInit(cpGearJoint joint, cpBody a, cpBody b, cpFloat phase, cpFloat ratio); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpConstraint cpGearJointNew(cpBody a, cpBody b, cpFloat phase, cpFloat ratio); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpGearJointSetPhase(cpConstraint constraint, cpFloat phase); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpGearJointSetRatio(cpConstraint constraint, cpFloat ratio); + + //[DllImport (ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + //internal static extern cpGrooveJoint cpGrooveJointAlloc(); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern Vect cpGrooveJointGetAnchorB(cpConstraint constraint); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern Vect cpGrooveJointGetGrooveA(cpConstraint constraint); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern Vect cpGrooveJointGetGrooveB(cpConstraint constraint); + + //[DllImport (ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + //internal static extern cpGrooveJoint cpGrooveJointInit(cpGrooveJoint joint, cpBody a, cpBody b, Vect groove_a, Vect groove_b, Vect anchorB); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpConstraint cpGrooveJointNew(cpBody a, cpBody b, Vect groove_a, Vect groove_b, Vect anchorB); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpGrooveJointSetAnchorB(cpConstraint constraint, Vect anchorB); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpGrooveJointSetGrooveA(cpConstraint constraint, Vect grooveA); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpGrooveJointSetGrooveB(cpConstraint constraint, Vect grooveB); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpHastySpaceFree(cpSpace space); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern uint cpHastySpaceGetThreads(cpSpace space); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpSpace cpHastySpaceNew(); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpHastySpaceSetThreads(cpSpace space, uint threads); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpHastySpaceStep(cpSpace space, cpFloat dt); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpMarchHard( + BoundingBox bb, uint x_samples, uint y_samples, cpFloat threshold, + cpMarchSegmentFunc segment, IntPtr segment_data, + cpMarchSampleFunc sample, IntPtr sample_data + ); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpMarchSoft( + BoundingBox bb, uint x_samples, uint y_samples, cpFloat threshold, + cpMarchSegmentFunc segment, IntPtr segment_data, + cpMarchSampleFunc sample, IntPtr sample_data + ); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpFloat cpMomentForBox(cpFloat m, cpFloat width, cpFloat height); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpFloat cpMomentForBox2(cpFloat m, BoundingBox box); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpFloat cpMomentForCircle(cpFloat m, cpFloat r1, cpFloat r2, Vect offset); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpFloat cpMomentForPoly(cpFloat m, int count, cpVectPointer verts, Vect offset, cpFloat radius); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpFloat cpMomentForSegment(cpFloat m, Vect a, Vect b, cpFloat radius); + + //[DllImport (ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + //internal static extern cpPinJoint cpPinJointAlloc(); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern Vect cpPinJointGetAnchorA(cpConstraint constraint); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern Vect cpPinJointGetAnchorB(cpConstraint constraint); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpFloat cpPinJointGetDist(cpConstraint constraint); + + //[DllImport (ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + //internal static extern cpPinJoint cpPinJointInit(cpPinJoint joint, cpBody a, cpBody b, Vect anchorA, Vect anchorB); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpConstraint cpPinJointNew(cpBody a, cpBody b, Vect anchorA, Vect anchorB); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpPinJointSetAnchorA(cpConstraint constraint, Vect anchorA); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpPinJointSetAnchorB(cpConstraint constraint, Vect anchorB); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpPinJointSetDist(cpConstraint constraint, cpFloat dist); + + //[DllImport (ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + //internal static extern cpPivotJoint cpPivotJointAlloc(); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern Vect cpPivotJointGetAnchorA(cpConstraint constraint); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern Vect cpPivotJointGetAnchorB(cpConstraint constraint); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + //internal static extern cpPivotJoint cpPivotJointInit(cpPivotJoint joint, cpBody a, cpBody b, Vect anchorA, Vect anchorB); + + //[DllImport (ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpConstraint cpPivotJointNew(cpBody a, cpBody b, Vect pivot); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpConstraint cpPivotJointNew2(cpBody a, cpBody b, Vect anchorA, Vect anchorB); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpPivotJointSetAnchorA(cpConstraint constraint, Vect anchorA); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpPivotJointSetAnchorB(cpConstraint constraint, Vect anchorB); + + //[DllImport (ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + //internal static extern cpPolyShape cpPolyShapeAlloc(); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern int cpPolyShapeGetCount(cpShape shape); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpFloat cpPolyShapeGetRadius(cpShape shape); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern Vect cpPolyShapeGetVert(cpShape shape, int index); + + //[DllImport (ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + //internal static extern cpPolyShape cpPolyShapeInit(cpPolyShape poly, cpBody body, int count, cpVectPointer verts, Transform transform, cpFloat radius); + + //[DllImport (ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + //internal static extern cpPolyShape cpPolyShapeInitRaw(cpPolyShape poly, cpBody body, int count, cpVectPointer verts, cpFloat radius); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpShape cpPolyShapeNew(cpBody body, int count, cpVectPointer verts, Transform transform, cpFloat radius); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpShape cpPolyShapeNewRaw(cpBody body, int count, cpVectPointer verts, cpFloat radius); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpPolyShapeSetRadius(cpShape shape, cpFloat radius); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpPolyShapeSetVerts(cpShape shape, int count, cpVectPointer verts, Transform transform); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpPolyShapeSetVertsRaw(cpShape shape, int count, cpVectPointer verts); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpPolylineSet cpPolylineConvexDecomposition(cpPolyline line, cpFloat tol); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpPolylineFree(cpPolyline line); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpPolyline cpPolylineSimplifyCurves(cpPolyline line, cpFloat tol); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpPolylineSet cpPolylineSetAlloc(); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpPolylineSetCollectSegment(Vect v0, Vect v1, cpPolylineSet lines); + + //[DllImport (ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + //internal static extern void cpPolylineSetDestroy(cpPolylineSet set, cpBool freePolylines); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpPolylineSetFree(cpPolylineSet set, cpBool freePolylines); + + //[DllImport (ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + //internal static extern cpPolylineSet cpPolylineSetInit(cpPolylineSet set); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpPolylineSet cpPolylineSetNew(); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpPolyline cpPolylineSimplifyVertexes(cpPolyline line, cpFloat tol); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpPolyline cpPolylineToConvexHull(cpPolyline line, cpFloat tol); + + //[DllImport (ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + //internal static extern cpRatchetJoint cpRatchetJointAlloc(); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpFloat cpRatchetJointGetAngle(cpConstraint constraint); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpFloat cpRatchetJointGetPhase(cpConstraint constraint); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpFloat cpRatchetJointGetRatchet(cpConstraint constraint); + + //[DllImport (ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + //internal static extern cpRatchetJoint cpRatchetJointInit(cpRatchetJoint joint, cpBody a, cpBody b, cpFloat phase, cpFloat ratchet); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpConstraint cpRatchetJointNew(cpBody a, cpBody b, cpFloat phase, cpFloat ratchet); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpRatchetJointSetAngle(cpConstraint constraint, cpFloat angle); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpRatchetJointSetPhase(cpConstraint constraint, cpFloat phase); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpRatchetJointSetRatchet(cpConstraint constraint, cpFloat ratchet); + + //[DllImport (ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + //internal static extern cpRotaryLimitJoint cpRotaryLimitJointAlloc(); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpFloat cpRotaryLimitJointGetMax(cpConstraint constraint); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpFloat cpRotaryLimitJointGetMin(cpConstraint constraint); + + //[DllImport (ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + //internal static extern cpRotaryLimitJoint cpRotaryLimitJointInit(cpRotaryLimitJoint joint, cpBody a, cpBody b, cpFloat min, cpFloat max); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpConstraint cpRotaryLimitJointNew(cpBody a, cpBody b, cpFloat min, cpFloat max); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpRotaryLimitJointSetMax(cpConstraint constraint, cpFloat max); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpRotaryLimitJointSetMin(cpConstraint constraint, cpFloat min); + + //[DllImport (ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + //internal static extern cpSegmentShape cpSegmentShapeAlloc(); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern Vect cpSegmentShapeGetA(cpShape shape); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern Vect cpSegmentShapeGetB(cpShape shape); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern Vect cpSegmentShapeGetNormal(cpShape shape); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpFloat cpSegmentShapeGetRadius(cpShape shape); + + //[DllImport (ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + //internal static extern cpSegmentShape cpSegmentShapeInit(cpSegmentShape seg, cpBody body, Vect a, Vect b, cpFloat radius); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpShape cpSegmentShapeNew(cpBody body, Vect a, Vect b, cpFloat radius); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpSegmentShapeSetEndpoints(cpShape shape, Vect a, Vect b); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpSegmentShapeSetNeighbors(cpShape shape, Vect prev, Vect next); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpSegmentShapeSetRadius(cpShape shape, cpFloat radius); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern BoundingBox cpShapeCacheBB(cpShape shape); + + //[DllImport (ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + //internal static extern void cpShapeDestroy(cpShape shape); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpShapeFree(cpShape shape); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpFloat cpShapeGetArea(cpShape shape); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern BoundingBox cpShapeGetBB(cpShape shape); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpBody cpShapeGetBody(cpShape shape); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern Vect cpShapeGetCenterOfGravity(cpShape shape); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpCollisionType cpShapeGetCollisionType(cpShape shape); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpFloat cpShapeGetDensity(cpShape shape); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpFloat cpShapeGetElasticity(cpShape shape); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpFloat cpShapeGetFriction(cpShape shape); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpFloat cpShapeGetMass(cpShape shape); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpFloat cpShapeGetMoment(cpShape shape); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpBool cpShapeGetSensor(cpShape shape); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpSpace cpShapeGetSpace(cpShape shape); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern Vect cpShapeGetSurfaceVelocity(cpShape shape); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpDataPointer cpShapeGetUserData(cpShape shape); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern ShapeFilter cpShapeGetFilter(cpShape shape); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpFloat cpShapePointQuery(cpShape shape, Vect p, ref cpPointQueryInfo output); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpBool cpShapeSegmentQuery(cpShape shape, Vect a, Vect b, cpFloat radius, ref cpSegmentQueryInfo info); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpShapeSetBody(cpShape shape, cpBody body); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpShapeSetCollisionType(cpShape shape, cpCollisionType collisionType); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpShapeSetDensity(cpShape shape, cpFloat density); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpShapeSetElasticity(cpShape shape, cpFloat elasticity); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpShapeSetFriction(cpShape shape, cpFloat friction); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpShapeSetMass(cpShape shape, cpFloat mass); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpShapeSetSensor(cpShape shape, cpBool sensor); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpShapeSetSurfaceVelocity(cpShape shape, Vect surfaceVelocity); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpShapeSetUserData(cpShape shape, cpDataPointer userData); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern Vect cpShapeSetFilter(cpShape shape, ShapeFilter filter); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern BoundingBox cpShapeUpdate(cpShape shape, Transform transform); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpContactPointSet cpShapesCollide(cpShape a, cpShape b); + + //[DllImport (ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + //internal static extern cpSimpleMotor cpSimpleMotorAlloc(); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpFloat cpSimpleMotorGetRate(cpConstraint constraint); + + //[DllImport (ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + //internal static extern cpSimpleMotor cpSimpleMotorInit(cpSimpleMotor joint, cpBody a, cpBody b, cpFloat rate); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpConstraint cpSimpleMotorNew(cpBody a, cpBody b, cpFloat rate); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpSimpleMotorSetRate(cpConstraint constraint, cpFloat rate); + + //[DllImport (ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + //internal static extern cpSlideJoint cpSlideJointAlloc(); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern Vect cpSlideJointGetAnchorA(cpConstraint constraint); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern Vect cpSlideJointGetAnchorB(cpConstraint constraint); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpFloat cpSlideJointGetMax(cpConstraint constraint); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpFloat cpSlideJointGetMin(cpConstraint constraint); + + //[DllImport (ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + //internal static extern cpSlideJoint cpSlideJointInit(cpSlideJoint joint, cpBody a, cpBody b, Vect anchorA, Vect anchorB, cpFloat min, cpFloat max); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpConstraint cpSlideJointNew(cpBody a, cpBody b, Vect anchorA, Vect anchorB, cpFloat min, cpFloat max); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpSlideJointSetAnchorA(cpConstraint constraint, Vect anchorA); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpSlideJointSetAnchorB(cpConstraint constraint, Vect anchorB); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpSlideJointSetMax(cpConstraint constraint, cpFloat max); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpSlideJointSetMin(cpConstraint constraint, cpFloat min); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpBody cpSpaceAddBody(cpSpace space, cpBody body); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpCollisionHandlerPointer cpSpaceAddCollisionHandler(cpSpace space, cpCollisionType a, cpCollisionType b); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpConstraint cpSpaceAddConstraint(cpSpace space, cpConstraint constraint); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpCollisionHandlerPointer cpSpaceAddDefaultCollisionHandler(cpSpace space); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpBool cpSpaceAddPostStepCallback(cpSpace space, cpPostStepFunc func, IntPtr key, IntPtr data); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpShape cpSpaceAddShape(cpSpace space, cpShape shape); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpCollisionHandlerPointer cpSpaceAddWildcardHandler(cpSpace space, cpCollisionType type); + + //[DllImport (ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + //internal static extern cpSpace cpSpaceAlloc(); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpSpaceBBQuery(cpSpace space, BoundingBox bb, ShapeFilter filter, cpSpaceBBQueryFunc func, IntPtr data); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpBool cpSpaceContainsShape(cpSpace space, cpShape shape); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpBool cpSpaceContainsBody(cpSpace space, cpBody body); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpBool cpSpaceContainsConstraint(cpSpace space, cpConstraint constraint); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpSpaceDebugDraw(cpSpace space, cpSpaceDebugDrawOptionsPointer options); + + //[DllImport (ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + //internal static extern void cpSpaceDestroy(cpSpace space); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpSpaceEachBody(cpSpace space, cpSpaceBodyIteratorFunc func, IntPtr data); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpSpaceEachConstraint(cpSpace space, cpSpaceConstraintIteratorFunc func, IntPtr data); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern int cpSpaceGetBodyCount(cpSpace space); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpSpaceGetBodiesUserDataArray(cpSpace space, IntPtr userDataArray); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern int cpSpaceGetDynamicBodyCount(cpSpace space); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpSpaceGetDynamicBodiesUserDataArray(cpSpace space, IntPtr userDataArray); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpSpaceEachShape(cpSpace space, cpSpaceShapeIteratorFunc func, IntPtr data); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpSpaceFree(cpSpace space); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpFloat cpSpaceGetCollisionBias(cpSpace space); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpTimestamp cpSpaceGetCollisionPersistence(cpSpace space); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpFloat cpSpaceGetCollisionSlop(cpSpace space); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpFloat cpSpaceGetCurrentTimeStep(cpSpace space); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpFloat cpSpaceGetDamping(cpSpace space); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern Vect cpSpaceGetGravity(cpSpace space); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpFloat cpSpaceGetIdleSpeedThreshold(cpSpace space); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern int cpSpaceGetIterations(cpSpace space); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpFloat cpSpaceGetSleepTimeThreshold(cpSpace space); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpBody cpSpaceGetStaticBody(cpSpace space); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpDataPointer cpSpaceGetUserData(cpSpace space); + + //[DllImport (ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + //internal static extern cpSpaceHash cpSpaceHashAlloc(); + + //[DllImport (ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + //internal static extern cpSpatialIndex cpSpaceHashInit(cpSpaceHash hash, cpFloat celldim, int numcells, cpSpatialIndexBBFunc bbfunc, cpSpatialIndex staticIndex); + + //[DllImport (ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + //internal static extern cpSpatialIndex cpSpaceHashNew(cpFloat celldim, int cells, cpSpatialIndexBBFunc bbfunc, cpSpatialIndex staticIndex); + + //[DllImport (ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + //internal static extern void cpSpaceHashResize(cpSpaceHash hash, cpFloat celldim, int numcells); + + //[DllImport (ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + //internal static extern cpSpace cpSpaceInit(cpSpace space); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpBool cpSpaceIsLocked(cpSpace space); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpSpace cpSpaceNew(); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpSpacePointQuery(cpSpace space, Vect point, cpFloat maxDistance, ShapeFilter filter, cpSpacePointQueryFunc func, IntPtr data); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpShape cpSpacePointQueryNearest(cpSpace space, Vect point, cpFloat maxDistance, ShapeFilter filter, ref cpPointQueryInfo output); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpSpaceReindexShape(cpSpace space, cpShape shape); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpSpaceReindexShapesForBody(cpSpace space, cpBody body); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpSpaceReindexStatic(cpSpace space); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpSpaceRemoveBody(cpSpace space, cpBody body); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpSpaceRemoveConstraint(cpSpace space, cpConstraint constraint); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpSpaceRemoveShape(cpSpace space, cpShape shape); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpSpaceSegmentQuery(cpSpace space, Vect start, Vect end, cpFloat radius, ShapeFilter filter, cpSpaceSegmentQueryFunc func, IntPtr data); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpShape cpSpaceSegmentQueryFirst(cpSpace space, Vect start, Vect end, cpFloat radius, ShapeFilter filter, ref cpSegmentQueryInfo output); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpSpaceSetCollisionBias(cpSpace space, cpFloat collisionBias); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpSpaceSetCollisionPersistence(cpSpace space, cpTimestamp collisionPersistence); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpSpaceSetCollisionSlop(cpSpace space, cpFloat collisionSlop); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpSpaceSetDamping(cpSpace space, cpFloat damping); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpSpaceSetGravity(cpSpace space, Vect gravity); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpSpaceSetIdleSpeedThreshold(cpSpace space, cpFloat idleSpeedThreshold); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpSpaceSetIterations(cpSpace space, int iterations); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpSpaceSetSleepTimeThreshold(cpSpace space, cpFloat sleepTimeThreshold); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpSpaceSetUserData(cpSpace space, cpDataPointer userData); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern cpBool cpSpaceShapeQuery(cpSpace space, cpShape shape, cpSpaceShapeQueryFunc func, IntPtr data); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpSpaceStep(cpSpace space, cpFloat dt); + + [DllImport(ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void cpSpaceUseSpatialHash(cpSpace space, cpFloat dim, int count); + + //[DllImport (ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + //internal static extern void cpSpatialIndexCollideStatic(cpSpatialIndex dynamicIndex, cpSpatialIndex staticIndex, cpSpatialIndexQueryFunc func, IntPtr data); + + //[DllImport (ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + //internal static extern void cpSpatialIndexFree(cpSpatialIndex index); + + //[DllImport (ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + //internal static extern cpSweep1D cpSweep1DAlloc(); + + //[DllImport (ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + //internal static extern cpSpatialIndex cpSweep1DInit(cpSweep1D sweep, cpSpatialIndexBBFunc bbfunc, cpSpatialIndex staticIndex); + + //[DllImport (ChipmunkLibraryName, CallingConvention = CallingConvention.Cdecl)] + //internal static extern cpSpatialIndex cpSweep1DNew(cpSpatialIndexBBFunc bbfunc, cpSpatialIndex staticIndex); + +#pragma warning restore IDE1006 // Naming Styles + + } +} diff --git a/src/Tizen.NUI.Physics2D/src/internal/chipmunk/PostStepCallbackInfo.cs b/src/Tizen.NUI.Physics2D/src/internal/chipmunk/PostStepCallbackInfo.cs new file mode 100644 index 0000000..05cbdc1 --- /dev/null +++ b/src/Tizen.NUI.Physics2D/src/internal/chipmunk/PostStepCallbackInfo.cs @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2023 Codefoco (codefoco@codefoco.com) + * + * 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. + */ + +using System; +using System.Collections.Generic; +using System.Text; + +namespace Tizen.NUI.Physics2D.Chipmunk +{ + /// + /// This class stores the data for the post-step callback. + /// + internal class PostStepCallbackInfo + { + Action callback; + object data; + + /// + /// Creates an instance of the PostStepCallbackInfo class. + /// + /// The post-step callback. + /// The data for the callback. + public PostStepCallbackInfo(Action c, object d) + { + callback = c; + data = d; + } + + /// + /// The post-step callback. + /// + public Action Callback => callback; + + /// + /// The data for the callback. + /// + public object Data => data; + } +} diff --git a/src/Tizen.NUI.Physics2D/src/internal/chipmunk/cpCollisionHandler.cs b/src/Tizen.NUI.Physics2D/src/internal/chipmunk/cpCollisionHandler.cs new file mode 100644 index 0000000..22a266e --- /dev/null +++ b/src/Tizen.NUI.Physics2D/src/internal/chipmunk/cpCollisionHandler.cs @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2023 Codefoco (codefoco@codefoco.com) + * + * 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. + */ + +using System.Runtime.InteropServices; +using cpCollisionFunction = System.IntPtr; +using cpCollisionHandlerPointer = System.IntPtr; +using cpCollisionType = System.UIntPtr; +using cpDataPointer = System.IntPtr; + +namespace Tizen.NUI.Physics2D.Chipmunk +{ + /// + /// Struct that holds function callback pointers to configure custom collision handling. + /// Collision handlers have a pair of types; + /// when a collision occurs between two shapes that have these types, the collision handler functions are triggered. + /// + [StructLayout(LayoutKind.Sequential)] + internal struct cpCollisionHandler + { + /// + /// Collision type identifier of the first shape that this handler recognizes. + /// In the collision handler callback, the shape with this type will be the first argument. Read only. + /// + public cpCollisionType typeA; + + /// + /// Collision type identifier of the second shape that this handler recognizes. + /// In the collision handler callback, the shape with this type will be the second argument. Read only. + /// + public cpCollisionType typeB; + + /// + /// This function is called when two shapes with types that match this collision handler begin colliding. + /// + public cpCollisionFunction beginFunction; + + /// + /// This function is called each step when two shapes with types that match this collision handler are colliding. + /// It's called before the collision solver runs so that you can affect a collision's outcome. + /// + public cpCollisionFunction preSolveFunction; + + /// + /// This function is called each step when two shapes with types that match this collision handler are colliding. + /// It's called after the collision solver runs so that you can read back information about the collision to trigger events in your game. + /// + public cpCollisionFunction postSolveFunction; + + /// + /// This function is called when two shapes with types that match this collision handler stop colliding. + /// + public cpCollisionFunction separateFunction; + + /// + /// This is a user definable context pointer that is passed to all of the collision handler functions. + /// + public cpDataPointer userData; + + public static cpCollisionHandler FromHandle(cpCollisionHandlerPointer handle) + { + return Marshal.PtrToStructure(handle); + } + + internal static void ToPointer(cpCollisionHandler handler, cpCollisionFunction handle) + { + Marshal.StructureToPtr(handler, handle, false); + } + } +} diff --git a/src/Tizen.NUI.Physics2D/src/internal/chipmunk/cpContactPoint.cs b/src/Tizen.NUI.Physics2D/src/internal/chipmunk/cpContactPoint.cs new file mode 100644 index 0000000..ed3f8ef --- /dev/null +++ b/src/Tizen.NUI.Physics2D/src/internal/chipmunk/cpContactPoint.cs @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2023 Codefoco (codefoco@codefoco.com) + * + * 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. + */ + +using System.Runtime.InteropServices; + +namespace Tizen.NUI.Physics2D.Chipmunk +{ + /// + /// The array of contact points. + /// + [StructLayout(LayoutKind.Sequential)] + internal struct cpContactPoint + { + /// + /// The position of the contact on the surface of the first shape. + /// + public Vect pointA; + + /// + /// The position of the contact on the surface of the second shape. + /// + public Vect pointB; + + /// + /// Penetration distance of the two shapes. Overlapping means it will be negative. + /// + public double distance; + } +} diff --git a/src/Tizen.NUI.Physics2D/src/internal/chipmunk/cpContactPointSet.cs b/src/Tizen.NUI.Physics2D/src/internal/chipmunk/cpContactPointSet.cs new file mode 100644 index 0000000..82c0d8f --- /dev/null +++ b/src/Tizen.NUI.Physics2D/src/internal/chipmunk/cpContactPointSet.cs @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2023 Codefoco (codefoco@codefoco.com) + * + * 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. + */ + +using System.Runtime.InteropServices; + +namespace Tizen.NUI.Physics2D.Chipmunk +{ + /// + /// A struct that wraps up the important collision data for an arbiter. + /// + [StructLayout(LayoutKind.Sequential)] + internal struct cpContactPointSet + { + /// + /// The number of contact points in the set. + /// + public int count; + + /// + /// The normal of the collision. + /// + public Vect normal; + + /// + /// The first contact point. + /// + public cpContactPoint points0; + + /// + /// The second contact point. + /// + public cpContactPoint points1; + } +} diff --git a/src/Tizen.NUI.Physics2D/src/internal/chipmunk/cpPointQueryInfo.cs b/src/Tizen.NUI.Physics2D/src/internal/chipmunk/cpPointQueryInfo.cs new file mode 100644 index 0000000..fc9bfb5 --- /dev/null +++ b/src/Tizen.NUI.Physics2D/src/internal/chipmunk/cpPointQueryInfo.cs @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2023 Codefoco (codefoco@codefoco.com) + * + * 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. + */ + +using System; +using System.Runtime.InteropServices; + +namespace Tizen.NUI.Physics2D.Chipmunk +{ + /// + /// Point query info. + /// + [StructLayout(LayoutKind.Sequential)] + internal struct cpPointQueryInfo + { + /// + /// The nearest shape, null if no shape was within range. + /// + public IntPtr shape; + + /// + /// The closest point on the shape's surface. (in world space coordinates) + /// + public Vect point; + + /// + /// The distance to the point. The distance is negative if the point is inside the shape. + /// + public double distance; + + /// + /// The gradient of the signed distance function. + /// + public Vect gradient; + } +} diff --git a/src/Tizen.NUI.Physics2D/src/internal/chipmunk/cpPolyline.cs b/src/Tizen.NUI.Physics2D/src/internal/chipmunk/cpPolyline.cs new file mode 100644 index 0000000..0278215 --- /dev/null +++ b/src/Tizen.NUI.Physics2D/src/internal/chipmunk/cpPolyline.cs @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2023 Codefoco (codefoco@codefoco.com) + * + * 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. + */ + +using System; +using System.Runtime.InteropServices; + +namespace Tizen.NUI.Physics2D.Chipmunk +{ + /// + /// Polylines are just arrays of vertices. + /// They are looped if the first vertex is equal to the last. + /// + [StructLayout(LayoutKind.Sequential)] + internal struct cpPolyline + { + /// + /// The number of vertices. + /// + public int count; + + /// + /// The capacity of the vertex array. + /// + public int capacity; + + /// + /// The vertex array that stores the vertices. + /// + public IntPtr verts; + } +} diff --git a/src/Tizen.NUI.Physics2D/src/internal/chipmunk/cpSegmentQueryInfo.cs b/src/Tizen.NUI.Physics2D/src/internal/chipmunk/cpSegmentQueryInfo.cs new file mode 100644 index 0000000..2804746 --- /dev/null +++ b/src/Tizen.NUI.Physics2D/src/internal/chipmunk/cpSegmentQueryInfo.cs @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2023 Codefoco (codefoco@codefoco.com) + * + * 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. + */ + +using System; +using System.Runtime.InteropServices; + +namespace Tizen.NUI.Physics2D.Chipmunk +{ + /// + /// Segment query info + /// + [StructLayout(LayoutKind.Sequential)] + internal struct cpSegmentQueryInfo + { + /// + /// The shape that was hit, or null if no collision occured. + /// + public IntPtr shape; + + /// + /// The point of impact. + /// + public Vect point; + + /// + /// The normal of the surface hit. + /// + public Vect normal; + + /// + /// The normalized distance along the query segment in the range [0, 1]. + /// + public double alpha; + } +} diff --git a/src/Tizen.NUI.Physics2D/src/internal/chipmunk/cpSpaceDebugDrawOptions.cs b/src/Tizen.NUI.Physics2D/src/internal/chipmunk/cpSpaceDebugDrawOptions.cs new file mode 100644 index 0000000..18e7fd7 --- /dev/null +++ b/src/Tizen.NUI.Physics2D/src/internal/chipmunk/cpSpaceDebugDrawOptions.cs @@ -0,0 +1,226 @@ +/* + * Copyright (c) 2023 Codefoco (codefoco@codefoco.com) + * + * 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. + */ + +using System; +using System.Runtime.InteropServices; +using cpDataPointer = System.IntPtr; +using cpShape = System.IntPtr; +using cpSpaceDebugDrawCircleImpl = System.IntPtr; +using cpSpaceDebugDrawColorForShapeImpl = System.IntPtr; +using cpSpaceDebugDrawDotImpl = System.IntPtr; +using cpSpaceDebugDrawFatSegmentImpl = System.IntPtr; +using cpSpaceDebugDrawFlags = System.Int32; +using cpSpaceDebugDrawPolygonImpl = System.IntPtr; +using cpSpaceDebugDrawSegmentImpl = System.IntPtr; +using cpVertPointer = System.IntPtr; +using voidptr_t = System.IntPtr; + +#if __IOS__ || __TVOS__ || __WATCHOS__ || __MACCATALYST__ +using ObjCRuntime; +#endif + +namespace Tizen.NUI.Physics2D.Chipmunk +{ + /// + /// Struct used with Space.DebugDraw() containing drawing callbacks and other drawing settings. + /// + [StructLayout(LayoutKind.Sequential)] + internal struct cpSpaceDebugDrawOptions + { + /// + /// Function that will be invoked to draw circles. + /// + cpSpaceDebugDrawCircleImpl drawCircle; + + /// + /// Function that will be invoked to draw line segments. + /// + cpSpaceDebugDrawSegmentImpl drawSegment; + + /// + /// Function that will be invoked to draw thick line segments. + /// + cpSpaceDebugDrawFatSegmentImpl drawFatSegment; + + /// + /// Function that will be invoked to draw convex polygons. + /// + cpSpaceDebugDrawPolygonImpl drawPolygon; + + /// + /// Function that will be invoked to draw dots. + /// + cpSpaceDebugDrawDotImpl drawDot; + + /// + /// Flags that request which things to draw (collision shapes, constraints, contact points). + /// + cpSpaceDebugDrawFlags flags; + + /// + /// Outline color passed to the drawing function. + /// + DebugColor shapeOutlineColor; + + /// + /// Function that decides what fill color to draw shapes using. + /// + cpSpaceDebugDrawColorForShapeImpl colorForShape; + + /// + /// Color passed to drawing functions for constraints. + /// + DebugColor constraintColor; + + /// + /// Color passed to drawing functions for collision points. + /// + DebugColor collisionPointColor; + + /// + /// User defined context pointer passed to all of the callback functions as the 'data' argument. + /// + cpDataPointer data; + + private IntPtr ToPointer() + { + IntPtr drawOptionsPtr = NativeInterop.AllocStructure(); + + Marshal.StructureToPtr(this, drawOptionsPtr, false); + return drawOptionsPtr; + } + + +#if __IOS__ || __TVOS__ || __WATCHOS__ || __MACCATALYST__ +#pragma warning disable CA1416 // Validate platform compatibility + [MonoPInvokeCallback(typeof(SpaceDebugDrawCircleImpl))] +#pragma warning restore CA1416 // Validate platform compatibility +#endif + private static void SpaceDebugDrawCircleCallback(Vect pos, double angle, double radius, DebugColor outlineColor, DebugColor fillColor, voidptr_t data) + { + IDebugDraw debugDraw = NativeInterop.FromIntPtr(data); + + debugDraw.DrawCircle(pos, angle, radius, outlineColor, fillColor); + } + + private static SpaceDebugDrawCircleImpl spaceDebugDrawCircleCallback = SpaceDebugDrawCircleCallback; + +#if __IOS__ || __TVOS__ || __WATCHOS__ || __MACCATALYST__ +#pragma warning disable CA1416 // Validate platform compatibility + [MonoPInvokeCallback(typeof(SpaceDebugDrawSegmentImpl))] +#pragma warning restore CA1416 // Validate platform compatibility +#endif + private static void SpaceDebugDrawSegmentCallback(Vect a, Vect b, DebugColor color, voidptr_t data) + { + IDebugDraw debugDraw = NativeInterop.FromIntPtr(data); + + debugDraw.DrawSegment(a, b, color); + } + + private static SpaceDebugDrawSegmentImpl spaceDebugDrawSegmentCallback = SpaceDebugDrawSegmentCallback; + +#if __IOS__ || __TVOS__ || __WATCHOS__ || __MACCATALYST__ +#pragma warning disable CA1416 // Validate platform compatibility + [MonoPInvokeCallback(typeof(SpaceDebugDrawFatSegmentImpl))] +#pragma warning restore CA1416 // Validate platform compatibility +#endif + private static void SpaceDebugDrawFatSegmentCallback(Vect a, Vect b, double radius, DebugColor outlineColor, DebugColor fillColor, voidptr_t data) + { + IDebugDraw debugDraw = NativeInterop.FromIntPtr(data); + + debugDraw.DrawFatSegment(a, b, radius, outlineColor, fillColor); + } + + private static SpaceDebugDrawFatSegmentImpl spaceDebugDrawFatSegmentCallback = SpaceDebugDrawFatSegmentCallback; + +#if __IOS__ || __TVOS__ || __WATCHOS__ || __MACCATALYST__ +#pragma warning disable CA1416 // Validate platform compatibility + [MonoPInvokeCallback(typeof(SpaceDebugDrawPolygonImpl))] +#pragma warning restore CA1416 // Validate platform compatibility +#endif + private static void SpaceDebugDrawPolygonCallback(int count, cpVertPointer verts, double radius, DebugColor outlineColor, DebugColor fillColor, voidptr_t data) + { + IDebugDraw debugDraw = NativeInterop.FromIntPtr(data); + + Vect[] vectors = NativeInterop.PtrToStructureArray(verts, count); + + debugDraw.DrawPolygon(vectors, radius, outlineColor, fillColor); + } + + private static SpaceDebugDrawPolygonImpl spaceDebugDrawPolygonCallback = SpaceDebugDrawPolygonCallback; + +#if __IOS__ || __TVOS__ || __WATCHOS__ || __MACCATALYST__ +#pragma warning disable CA1416 // Validate platform compatibility + [MonoPInvokeCallback(typeof(SpaceDebugDrawDotImpl))] +#pragma warning restore CA1416 // Validate platform compatibility +#endif + private static void SpaceDebugDrawDotCallback(double size, Vect pos, DebugColor color, voidptr_t data) + { + IDebugDraw debugDraw = NativeInterop.FromIntPtr(data); + + debugDraw.DrawDot(size, pos, color); + } + + private static SpaceDebugDrawDotImpl spaceDebugDrawDotCallback = SpaceDebugDrawDotCallback; + +#if __IOS__ || __TVOS__ || __WATCHOS__ || __MACCATALYST__ +#pragma warning disable CA1416 // Validate platform compatibility + [MonoPInvokeCallback(typeof(SpaceDebugDrawColorForShapeImpl))] +#pragma warning restore CA1416 // Validate platform compatibility +#endif + private static DebugColor SpaceDebugDrawColorForShapeCallback(cpShape handleShape, voidptr_t data) + { + IDebugDraw debugDraw = NativeInterop.FromIntPtr(data); + var shape = Shape.FromHandle(handleShape); + + return debugDraw.ColorForShape(shape); + } + + private static SpaceDebugDrawColorForShapeImpl spaceDebugDrawColorForShapeCallback = SpaceDebugDrawColorForShapeCallback; + + + public IntPtr AcquireDebugDrawOptions(IDebugDraw debugDraw, DebugDrawFlags flags, DebugDrawColors colors) + { + this.flags = (int)flags; + collisionPointColor = colors.CollisionPoint; + constraintColor = colors.Constraint; + shapeOutlineColor = colors.ShapeOutline; + + drawCircle = spaceDebugDrawCircleCallback.ToFunctionPointer(); + drawSegment = spaceDebugDrawSegmentCallback.ToFunctionPointer(); + drawFatSegment = spaceDebugDrawFatSegmentCallback.ToFunctionPointer(); + drawPolygon = spaceDebugDrawPolygonCallback.ToFunctionPointer(); + drawDot = spaceDebugDrawDotCallback.ToFunctionPointer(); + colorForShape = spaceDebugDrawColorForShapeCallback.ToFunctionPointer(); + + data = NativeInterop.RegisterHandle(debugDraw); + + return ToPointer(); + } + + public void ReleaseDebugDrawOptions(IntPtr debugDrawOptionsPointer) + { + NativeInterop.ReleaseHandle(data); + NativeInterop.FreeStructure(debugDrawOptionsPointer); + } + } +} diff --git a/src/Tizen.NUI.Physics2D/src/public/chipmunk/Arbiter.cs b/src/Tizen.NUI.Physics2D/src/public/chipmunk/Arbiter.cs new file mode 100644 index 0000000..0a7a05a --- /dev/null +++ b/src/Tizen.NUI.Physics2D/src/public/chipmunk/Arbiter.cs @@ -0,0 +1,387 @@ +/* + * Copyright (c) 2023 Codefoco (codefoco@codefoco.com) + * + * 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. + */ + +using System; +using System.Collections.Generic; +using System.ComponentModel; +using cpArbiter = System.IntPtr; + +namespace Tizen.NUI.Physics2D.Chipmunk +{ + /// + /// The object encapsulates a pair of colliding shapes and all of the data + /// about their collision. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public struct Arbiter : IEquatable + { +#pragma warning disable IDE0032 + readonly cpArbiter arbiter; +#pragma warning restore IDE0032 + + /// + /// Native handle of . + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public cpArbiter Handle => arbiter; + + internal Arbiter(cpArbiter handle) + { + arbiter = handle; + } + + /// + /// The restitution (elasticity) that will be applied to the pair of colliding objects. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public double Restitution + { + get => NativeMethods.cpArbiterGetRestitution(arbiter); + set => NativeMethods.cpArbiterSetRestitution(arbiter, value); + } + + /// + /// Friction coefficient that will be applied to the pair of colliding objects. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public double Friction + { + get => NativeMethods.cpArbiterGetFriction(arbiter); + set => NativeMethods.cpArbiterSetFriction(arbiter, value); + } + + /// + /// The relative surface velocity of the two shapes in contact. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public Vect SurfaceVelocity + { + get => NativeMethods.cpArbiterGetSurfaceVelocity(arbiter); + set => NativeMethods.cpArbiterSetSurfaceVelocity(arbiter, value); + } + + /// + /// Calculate the total impulse including the friction that was applied by this arbiter. + /// This function should only be called from a post-solve, post-step or cpBodyEachArbiter + /// callback. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public Vect TotalImpulse => NativeMethods.cpArbiterTotalImpulse(arbiter); + + /// + /// Calculate the amount of energy lost in a collision including static, but not dynamic friction. + /// This function should only be called from a post-solve, post-step or cpBodyEachArbiter callback. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public double TotalKE => NativeMethods.cpArbiterTotalKE(arbiter); + + /// + /// Mark a collision pair to be ignored until the two objects separate. Pre-solve and + /// post-solve callbacks will not be called, but the separate callback will be called. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public bool Ignore() => NativeMethods.cpArbiterIgnore(arbiter) != 0; + + /// + /// Return the colliding shapes involved for this arbiter. The order of their + /// values will match the order set when the collision + /// handler was registered. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public void GetShapes(out Shape a, out Shape b) + { + IntPtr ptrA; + IntPtr ptrB; + + NativeMethods.cpArbiterGetShapes(arbiter, out ptrA, out ptrB); + + a = Shape.FromHandle(ptrA); + b = Shape.FromHandle(ptrB); + } + + /// + /// Return the colliding bodies involved for this arbiter. The order of the + /// values the bodies are associated with will match the + /// order set when the collision handler was registered. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public void GetBodies(out Body a, out Body b) + { + IntPtr ptrA; + IntPtr ptrB; + + NativeMethods.cpArbiterGetBodies(arbiter, out ptrA, out ptrB); + + a = Body.FromHandle(ptrA); + b = Body.FromHandle(ptrB); + } + + /// + /// The contact point set for an arbiter. This can be a very powerful feature, but use it + /// with caution! + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public ContactPointSet ContactPointSet + { + get + { + cpContactPointSet pointSet = NativeMethods.cpArbiterGetContactPointSet(arbiter); + return ContactPointSet.FromContactPointSet(pointSet); + } + set + { + cpContactPointSet pointSet = value.ToContactPointSet(); + NativeMethods.cpArbiterSetContactPointSet(arbiter, ref pointSet); + } + } + + /// + /// Arbitrary user data. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public object Data + { + get + { + IntPtr handle = NativeMethods.cpArbiterGetUserData(arbiter); + + if (handle == IntPtr.Zero) + { + return null; + } + + return NativeInterop.FromIntPtrAndFree(handle); + } + set + { + var gcHandle = IntPtr.Zero; + + if (value != null) + { + gcHandle = NativeInterop.RegisterHandle(value); + } + + NativeMethods.cpArbiterSetUserData(arbiter, gcHandle); + } + } + + /// + /// Returns true if this is the first step a pair of objects started colliding. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public bool IsFirstContact => NativeMethods.cpArbiterIsFirstContact(arbiter) != 0; + + /// + /// Returns true if the separate callback is due to a shape being removed from the space. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public bool IsRemoval => NativeMethods.cpArbiterIsRemoval(arbiter) != 0; + + /// + /// Get the number of contact points for this arbiter. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public int Count => NativeMethods.cpArbiterGetCount(arbiter); + + /// + /// Get the normal of the collision. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public Vect Normal => NativeMethods.cpArbiterGetNormal(arbiter); + + /// + /// Get the position of the th contact point on the surface of the first + /// shape. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public Vect GetPointA(int i) + { + return NativeMethods.cpArbiterGetPointA(arbiter, i); + } + + /// + /// Get the position of the th contact point on the surface of the + /// second shape. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public Vect GetPointB(int i) + { + return NativeMethods.cpArbiterGetPointB(arbiter, i); + } + + /// + /// Get the depth (amount of overlap) of the th contact point. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public double GetDepth(int i) + { + return NativeMethods.cpArbiterGetDepth(arbiter, i); + } + + /// + /// If you want a custom callback to invoke the wildcard callback for the first collision + /// type, you must call this function explicitly. You must decide how to handle the + /// wildcard's return value since it may disagree with the other wildcard handler's return + /// value or your own. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public void CallWildcardBeginA(Space space) + { + NativeMethods.cpArbiterCallWildcardBeginA(arbiter, space.Handle); + } + + /// + /// If you want a custom callback to invoke the wildcard callback for the second collision + /// type, you must call this function explicitly. You must decide how to handle the + /// wildcard's return value since it may disagree with the other wildcard handler's return + /// value or your own. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public void CallWildcardBeginB(Space space) + { + NativeMethods.cpArbiterCallWildcardBeginB(arbiter, space.Handle); + } + + /// + /// If you want a custom callback to invoke the wildcard callback for the first collision + /// type, you must call this function explicitly. You must decide how to handle the + /// wildcard's return value since it may disagree with the other wildcard handler's return + /// value or your own. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public bool CallWildcardPreSolveA(Space space) + { + return NativeMethods.cpArbiterCallWildcardPreSolveA(arbiter, space.Handle) != 0; + } + + /// + /// If you want a custom callback to invoke the wildcard callback for the second collision + /// type, you must call this function explicitly. You must decide how to handle the + /// wildcard's return value since it may disagree with the other wildcard handler's return + /// value or your own. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public bool CallWildcardPreSolveB(Space space) + { + return NativeMethods.cpArbiterCallWildcardPreSolveB(arbiter, space.Handle) != 0; + } + + /// + /// If you want a custom callback to invoke the wildcard callback for the first collision + /// type, you must call this function explicitly. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public void CallWildcardPostSolveA(Space space) + { + NativeMethods.cpArbiterCallWildcardPostSolveA(arbiter, space.Handle); + } + + /// + /// If you want a custom callback to invoke the wildcard callback for the second collision + /// type, you must call this function explicitly. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public void CallWildcardPostSolveB(Space space) + { + NativeMethods.cpArbiterCallWildcardPostSolveB(arbiter, space.Handle); + } + + /// + /// If you want a custom callback to invoke the wildcard callback for the first collision + /// type, you must call this function explicitly. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public void CallWildcardSeparateA(Space space) + { + NativeMethods.cpArbiterCallWildcardSeparateA(arbiter, space.Handle); + } + + /// + /// If you want a custom callback to invoke the wildcard callback for the second collision + /// type, you must call this function explicitly. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public void CallWildcardSeparateB(Space space) + { + NativeMethods.cpArbiterCallWildcardSeparateB(arbiter, space.Handle); + } + + /// + /// Return true if an arbiter is equal to another. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public bool Equals(Arbiter other) + { + return arbiter == other.arbiter; + } + + /// + /// Check if an arbiter is equal to the given object. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public override bool Equals(object obj) + { + var other = obj as Arbiter?; + + if (other == null) + return false; + + return Equals(other.Value); + } + + /// + /// Return the arbiter's handle prefixed by 'Handle: '. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public override string ToString() + { + return $"Handle: {arbiter}"; + } + + /// + /// Get the hash code. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public override int GetHashCode() + { + return 932982278 + EqualityComparer.Default.GetHashCode(arbiter); + } + + /// + /// Check if one arbiter is equal to another. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public static bool operator ==(Arbiter left, Arbiter right) + { + return left.Equals(right); + } + + /// + /// Check if one arbiter is inequal to another. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public static bool operator !=(Arbiter left, Arbiter right) + { + return !(left == right); + } + } +} diff --git a/src/Tizen.NUI.Physics2D/src/public/chipmunk/AutoGeometry.cs b/src/Tizen.NUI.Physics2D/src/public/chipmunk/AutoGeometry.cs new file mode 100644 index 0000000..2a8ba0b --- /dev/null +++ b/src/Tizen.NUI.Physics2D/src/public/chipmunk/AutoGeometry.cs @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2023 Codefoco (codefoco@codefoco.com) + * + * 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. + */ + +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Runtime.InteropServices; + +#if __IOS__ || __TVOS__ || __WATCHOS__ || __MACCATALYST__ +using ObjCRuntime; +#endif + +namespace Tizen.NUI.Physics2D.Chipmunk +{ + /// + /// This class contains functions for automatic generation of geometry. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + internal static class AutoGeometry + { +#if __IOS__ || __TVOS__ || __WATCHOS__ || __MACCATALYST__ +#pragma warning disable CA1416 // Validate platform compatibility + [MonoPInvokeCallback(typeof(MarchSegmentFunction))] +#pragma warning restore CA1416 // Validate platform compatibility +#endif + private static void MarchSegmentFunctionCallback(Vect v0, Vect v1, IntPtr data) + { + var marchData = (MarchData)GCHandle.FromIntPtr(data).Target; + marchData.SegmentFunction(v0, v1, marchData.SegmentData); + } + + private static MarchSegmentFunction segmentFunctionCallback = MarchSegmentFunctionCallback; + +#if (__IOS__ || __TVOS__ || __WATCHOS__ || __MACCATALYST__) +#pragma warning disable CA1416 // Validate platform compatibility + [MonoPInvokeCallback(typeof(MarchSampleFunction))] +#pragma warning restore CA1416 // Validate platform compatibility +#endif + private static double MarchSampleFunctionCallBack(Vect point, IntPtr data) + { + var marchData = (MarchData)GCHandle.FromIntPtr(data).Target; + return marchData.SampleFunction(point, marchData.SampleData); + } + + private static MarchSampleFunction sampleFunctionCallBack = MarchSampleFunctionCallBack; + + /// + /// Trace an aliased curve of an image along a particular threshold. The given number of + /// samples will be taken and spread across the bounding box area using the sampling + /// function and context. The segment function will be called for each segment detected that + /// lies along the density contour for the threshold. Only the SegmentData and SampleData are + /// optional. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public static void MarchHard(MarchData data) + { + var gcHandle = GCHandle.Alloc(data); + IntPtr handlePtr = GCHandle.ToIntPtr(gcHandle); + + NativeMethods.cpMarchHard( + data.BoundingBox, + (uint)data.XSamples, + (uint)data.YSamples, + data.Threshold, + segmentFunctionCallback.ToFunctionPointer(), + handlePtr, + sampleFunctionCallBack.ToFunctionPointer(), + handlePtr); + + gcHandle.Free(); + } + + /// + /// Trace an anti-aliased contour of an image along a particular threshold. The given number + /// of samples will be taken and spread across the bounding box area using the sampling + /// function and context. The segment function will be called for each segment detected that + /// lies along the density contour for the threshold. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public static void MarchSoft(MarchData data) + { + var gcHandle = GCHandle.Alloc(data); + IntPtr handlePtr = GCHandle.ToIntPtr(gcHandle); + + NativeMethods.cpMarchSoft( + data.BoundingBox, + (uint)data.XSamples, + (uint)data.YSamples, + data.Threshold, + segmentFunctionCallback.ToFunctionPointer(), + handlePtr, + sampleFunctionCallBack.ToFunctionPointer(), + handlePtr); + + gcHandle.Free(); + } + } +} diff --git a/src/Tizen.NUI.Physics2D/src/public/chipmunk/Body.cs b/src/Tizen.NUI.Physics2D/src/public/chipmunk/Body.cs new file mode 100644 index 0000000..850b208 --- /dev/null +++ b/src/Tizen.NUI.Physics2D/src/public/chipmunk/Body.cs @@ -0,0 +1,767 @@ +/* + * Copyright (c) 2023 Codefoco (codefoco@codefoco.com) + * + * 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. + */ + +using System; +using System.ComponentModel; +using System.Runtime.InteropServices; +using System.Collections.Generic; + +#if __IOS__ || __TVOS__ || __WATCHOS__ || __MACCATALYST__ +using ObjCRuntime; +#endif + +using cpBody = System.IntPtr; +using cpArbiter = System.IntPtr; +using cpConstraint = System.IntPtr; +using cpShape = System.IntPtr; +using cpSpace = System.IntPtr; +using cpDataPointer = System.IntPtr; +using System.Diagnostics; + +namespace Tizen.NUI.Physics2D.Chipmunk +{ + /// + /// Mass and moment are ignored when is + /// or . Guessing the mass for a body is usually fine, but guessing + /// a moment of inertia can lead to a very poor simulation. It’s recommended to use Chipmunk’s + /// moment-calculating functions to estimate the moment for you. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public class Body : IDisposable + { +#pragma warning disable IDE0032 + private readonly cpBody body; +#pragma warning restore IDE0032 + + /// + /// The native handle. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public cpBody Handle => body; + + /// + /// Create a Dynamic Body with no mass and no moment. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public Body() + : this(BodyType.Dynamic) + { + } + + internal Body(cpBody handle) + { + body = handle; + RegisterUserData(); + } + + /// + /// Create a of the given . + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public Body(BodyType type) + { + body = InitializeBody(type); + RegisterUserData(); + } + + /// + /// Creates a body with the given mass and moment. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public Body(double mass, double moment) : this(mass, moment, BodyType.Dynamic) + { + } + + /// + /// Creates a body with the given mass and moment, of the give . + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public Body(double mass, double moment, BodyType type) + { + body = InitializeBody(type); + NativeMethods.cpBodySetMass(body, mass); + NativeMethods.cpBodySetMoment(body, moment); + RegisterUserData(); + } + + void RegisterUserData() + { + cpDataPointer pointer = NativeInterop.RegisterHandle(this); + NativeMethods.cpBodySetUserData(body, pointer); + } + + void ReleaseUserData() + { + cpDataPointer pointer = NativeMethods.cpBodyGetUserData(body); + NativeInterop.ReleaseHandle(pointer); + } + + /// + /// Get a object from a native cpBody handle. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public static Body FromHandle(cpBody body) + { + cpDataPointer handle = NativeMethods.cpBodyGetUserData(body); + return NativeInterop.FromIntPtr(handle); + } + + /// + /// Get the managed object from the native handle. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public static Body FromHandleSafe(cpBody nativeBodyHandle) + { + if (nativeBodyHandle == IntPtr.Zero) + { + return null; + } + + return FromHandle(nativeBodyHandle); + } + + private static cpBody InitializeBody(BodyType type) + { + if (type == BodyType.Kinematic) + { + return NativeMethods.cpBodyNewKinematic(); + } + + if (type == BodyType.Static) + { + return NativeMethods.cpBodyNewStatic(); + } + + return NativeMethods.cpBodyNew(0.0, 0.0); + } + + /// + /// Destroy and free the body. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public void Free() + { + var space = Space; + + if (space != null) + space.RemoveBody(this); + + ReleaseUserData(); + NativeMethods.cpBodyFree(body); + } + + /// + /// Dispose the body. + /// + protected virtual void Dispose(bool dispose) + { + if (!dispose) + { + Debug.WriteLine("Disposing body {0} on finalizer... (consider Dispose explicitly)", body); + } + + Free(); + } + + /// + /// Dispose the body. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + // Properties + + /// + /// Arbitrary user data. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public object Data { get; set; } + + /// + /// Rotation of the body in radians. When changing the rotation, you may also want to call + /// to update the collision detection information + /// for the attached shapes if you plan to make any queries against the space. A body + /// rotates around its center of gravity, not its position. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public double Angle + { + get => NativeMethods.cpBodyGetAngle(body); + set => NativeMethods.cpBodySetAngle(body, value); + } + + /// + /// Set body position and rotation angle (in radians) + /// + /// + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public void SetTransform(Vect position, double angle) + { + NativeMethods.cpBodySetTransform(body, position, angle); + } + + /// + /// Get body position and rotation angle (in radians) + /// + /// + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public void GetTransform(out Vect position, out double angle) + { + NativeMethods.cpBodyGetTransform(body, out position, out angle); + } + + /// + /// The way the body behaves in physics simulations. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public BodyType Type + { + get => (BodyType)NativeMethods.cpBodyGetType(body); + set => NativeMethods.cpBodySetType(body, (int)value); + } + + /// + /// Mass of the rigid body. Mass does not have to be expressed in any particular units, but + /// relative masses should be consistent. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public double Mass + { + get => NativeMethods.cpBodyGetMass(body); + set => NativeMethods.cpBodySetMass(body, value); + } + + /// + /// Moment of inertia of the body. The mass tells you how hard it is to push an object, + /// the MoI tells you how hard it is to spin the object. Don't try to guess the MoI, use the + /// MomentFor*() functions to estimate it, or the physics may behave strangely. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public double Moment + { + get => NativeMethods.cpBodyGetMoment(body); + set => NativeMethods.cpBodySetMoment(body, value); + } + + /// + /// Get the space this body is associated with, or null if it is not currently associated. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public Space Space + { + get + { + cpSpace space = NativeMethods.cpBodyGetSpace(body); + return Space.FromHandleSafe(space); + } + } + + /// + /// Position of the body. When changing the position, you may also want to call + /// to update the collision detection information + /// for the attached shapes if you plan to make any queries against the space. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public Vect Position + { + get => NativeMethods.cpBodyGetPosition(body); + set => NativeMethods.cpBodySetPosition(body, value); + } + + /// + /// Location of the center of gravity in body-local coordinates. The default value is + /// (0, 0), meaning the center of gravity is the same as the position of the body. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public Vect CenterOfGravity + { + get => NativeMethods.cpBodyGetCenterOfGravity(body); + set => NativeMethods.cpBodySetCenterOfGravity(body, value); + } + + /// + /// Linear velocity of the center of gravity of the body. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public Vect Velocity + { + get => NativeMethods.cpBodyGetVelocity(body); + set => NativeMethods.cpBodySetVelocity(body, value); + } + + /// + /// Force applied to the center of gravity of the body. This value is reset for every time + /// step. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public Vect Force + { + get => NativeMethods.cpBodyGetForce(body); + set => NativeMethods.cpBodySetForce(body, value); + } + + /// + /// The angular velocity of the body in radians per second. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public double AngularVelocity + { + get => NativeMethods.cpBodyGetAngularVelocity(body); + set => NativeMethods.cpBodySetAngularVelocity(body, value); + } + + /// + /// The torque applied to the body. This value is reset for every time step. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public double Torque + { + get => NativeMethods.cpBodyGetTorque(body); + set => NativeMethods.cpBodySetTorque(body, value); + } + +#if __IOS__ || __TVOS__ || __WATCHOS__ || __MACCATALYST__ +#pragma warning disable CA1416 // Validate platform compatibility + [MonoPInvokeCallback(typeof(BodyArbiterIteratorFunction))] +#pragma warning restore CA1416 // Validate platform compatibility +#endif + private static void AddEachArbiterToArray(cpBody body, cpArbiter arbiter, IntPtr data) + { + var list = (List)GCHandle.FromIntPtr(data).Target; + var a = new Arbiter(arbiter); + list.Add(a); + } + + private static BodyArbiterIteratorFunction eachArbiterFunc = AddEachArbiterToArray; + + /// + /// The rotation vector for the body. Can be used with cpvrotate() or cpvunrotate() to perform fast rotations. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public Vect Rotation => NativeMethods.cpBodyGetRotation(body); + + /// + /// Get the list of body Arbiters + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public IReadOnlyList Arbiters + { + get + { + var list = new List(); + var gcHandle = GCHandle.Alloc(list); + NativeMethods.cpBodyEachArbiter(body, eachArbiterFunc.ToFunctionPointer(), GCHandle.ToIntPtr(gcHandle)); + gcHandle.Free(); + return list; + } + } + +#if __IOS__ || __TVOS__ || __WATCHOS__ || __MACCATALYST__ +#pragma warning disable CA1416 // Validate platform compatibility + [MonoPInvokeCallback(typeof(BodyArbiterIteratorFunction))] +#pragma warning restore CA1416 // Validate platform compatibility +#endif + private static void AddEachConstraintToArray(cpBody body, cpConstraint constraint, IntPtr data) + { + var list = (List)GCHandle.FromIntPtr(data).Target; + var c = Constraint.FromHandle(constraint); + list.Add(c); + } + + private static BodyConstraintIteratorFunction eachConstraintFunc = AddEachConstraintToArray; + + /// + /// All constraints attached to the body + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public IReadOnlyList Constraints + { + get + { + var list = new List(); + var gcHandle = GCHandle.Alloc(list); + NativeMethods.cpBodyEachConstraint(body, eachConstraintFunc.ToFunctionPointer(), GCHandle.ToIntPtr(gcHandle)); + gcHandle.Free(); + return list.ToArray(); + } + } + +#if __IOS__ || __TVOS__ || __WATCHOS__ || __MACCATALYST__ +#pragma warning disable CA1416 // Validate platform compatibility + [MonoPInvokeCallback(typeof(BodyShapeIteratorFunction))] +#pragma warning restore CA1416 // Validate platform compatibility +#endif + private static void AddEachShapeToArray(cpBody body, cpShape shape, IntPtr data) + { + var list = (List)GCHandle.FromIntPtr(data).Target; + var s = Shape.FromHandle(shape); + list.Add(s); + } + + private static BodyShapeIteratorFunction eachShapeFunc = AddEachShapeToArray; + + /// + /// All shapes attached to the body + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public IReadOnlyList Shapes + { + get + { + var list = new List(); + var gcHandle = GCHandle.Alloc(list); + NativeMethods.cpBodyEachShape(body, eachShapeFunc.ToFunctionPointer(), GCHandle.ToIntPtr(gcHandle)); + gcHandle.Free(); + return list.ToArray(); + } + } + + /// + /// Returns true if body is sleeping. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public bool IsSleeping => NativeMethods.cpBodyIsSleeping(body) != 0; + + // Actions + + /// + /// Reset the idle timer on a body. + /// If it was sleeping, wake it and any other bodies it was touching. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public void Activate() => NativeMethods.cpBodyActivate(body); + + /// + /// Similar in function to Activate(). Activates all bodies touching body. If filter is not NULL, then only bodies touching through filter will be awoken. + /// + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public void ActivateStatic(Shape filter) => NativeMethods.cpBodyActivateStatic(body, filter.Handle); + + /// + /// Add the local force force to body as if applied from the body local point. + /// + /// + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public void ApplyForceAtLocalPoint(Vect force, Vect point) + { + NativeMethods.cpBodyApplyForceAtLocalPoint(body, force, point); + } + + /// + /// Apply torque. + /// + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public void ApplyTorque(double torque) + { + NativeMethods.cpBodyApplyTorque(body, torque); + } + + /// + /// Apply angular impulse. + /// + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public void ApplyAngularImpulse(double impulse) + { + NativeMethods.cpBodyApplyAngularImpulse(body, impulse); + } + + /// + /// Add the force force to body as if applied from the world point. + /// People are sometimes confused by the difference between a force and an impulse. + /// An impulse is a very large force applied over a very short period of time. + /// Some examples are a ball hitting a wall or cannon firing. + /// Chipmunk treats impulses as if they occur instantaneously by adding directly to the velocity of an object. + /// Both impulses and forces are affected the mass of an object. + /// Doubling the mass of the object will halve the effect. + /// + /// + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public void ApplyForceAtWorldPoint(Vect force, Vect point) + { + NativeMethods.cpBodyApplyForceAtWorldPoint(body, force, point); + } + + /// + /// Apply an impulse to a body. Both the impulse and point are expressed in world coordinates. + /// + /// + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public void ApplyImpulseAtWorldPoint(Vect impulse, Vect point) + { + NativeMethods.cpBodyApplyImpulseAtWorldPoint(body, impulse, point); + } + + /// + /// Apply an impulse to a body. Both the impulse and point are expressed in body local coordinates. + /// + /// + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public void ApplyImpulseAtLocalPoint(Vect impulse, Vect point) + { + NativeMethods.cpBodyApplyImpulseAtLocalPoint(body, impulse, point); + } + + /// + /// Forces a body to fall asleep immediately even if it’s in midair. Cannot be called from a callback. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public void Sleep() + { + NativeMethods.cpBodySleep(body); + } + + /// + /// When objects in Chipmunk sleep, they sleep as a group of all objects that are touching or jointed together. + /// When an object is woken up, all of the objects in its group are woken up. + /// SleepWithGroup() allows you group sleeping objects together. It acts identically to Sleep() if you pass null as + /// group by starting a new group. + /// If you pass a sleeping body for group, body will be awoken when group is awoken. + /// You can use this to initialize levels and start stacks of objects in a pre-sleeping state. + /// + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public void SleepWithGroup(Body group) + { + NativeMethods.cpBodySleepWithGroup(body, group != null ? group.Handle : IntPtr.Zero); + } + +#if __IOS__ || __TVOS__ || __WATCHOS__ || __MACCATALYST__ +#pragma warning disable CA1416 // Validate platform compatibility + [MonoPInvokeCallback(typeof(BodyVelocityFunction))] +#pragma warning restore CA1416 // Validate platform compatibility +#endif + private static void BodyVelocityFunctionCallback(cpBody bodyHandle, Vect gravity, double damping, double dt) + { + var body = FromHandle(bodyHandle); + + body.velocityUpdateFunction(body, gravity, damping, dt); + } + + private static BodyVelocityFunction BodyVelocityFunctionCallbackDelegate = BodyVelocityFunctionCallback; + + private Action velocityUpdateFunction; + /// + /// Set the callback used to update a body's velocity. + /// Parameters: body, gravity, damping and deltaTime + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public Action VelocityUpdateFunction + { + get => velocityUpdateFunction; + set + { + velocityUpdateFunction = value; + + IntPtr callbackPointer; + + if (value == null) + callbackPointer = NativeMethods.cpBodyGetDefaultVelocityUpdateFunc(); + else + callbackPointer = BodyVelocityFunctionCallbackDelegate.ToFunctionPointer(); + + NativeMethods.cpBodySetVelocityUpdateFunc(body, callbackPointer); + } + } + +#if __IOS__ || __TVOS__ || __WATCHOS__ || __MACCATALYST__ +#pragma warning disable CA1416 // Validate platform compatibility + [MonoPInvokeCallback(typeof(BodyPositionFunction))] +#pragma warning restore CA1416 // Validate platform compatibility +#endif + private static void BodyPositionFunctionCallback(cpBody bodyHandle, double dt) + { + var body = FromHandle(bodyHandle); + + body.positionUpdateFunction(body, dt); + } + + private static BodyPositionFunction BodyUpdateFunctionCallbackDelegate = BodyPositionFunctionCallback; + + private Action positionUpdateFunction; + + /// + /// Set the callback used to update a body's position. + /// Parameters: body, deltaTime + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public Action PositionUpdateFunction + { + get => positionUpdateFunction; + set + { + positionUpdateFunction = value; + + IntPtr callbackPointer; + + if (value == null) + callbackPointer = NativeMethods.cpBodyGetDefaultPositionUpdateFunc(); + else + callbackPointer = BodyUpdateFunctionCallbackDelegate.ToFunctionPointer(); + + NativeMethods.cpBodySetPositionUpdateFunc(body, callbackPointer); + } + } + + /// + /// Default velocity integration function.. + /// + /// + /// + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public void UpdateVelocity(Vect gravity, double damping, double dt) + { + NativeMethods.cpBodyUpdateVelocity(body, gravity, damping, dt); + } + + /// + /// Default position integration function. + /// + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public void UpdatePosition(double dt) + { + NativeMethods.cpBodyUpdatePosition(body, dt); + } + + /// + /// Convert body relative/local coordinates to absolute/world coordinates. + /// + /// + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public Vect LocalToWorld(Vect point) + { + return NativeMethods.cpBodyLocalToWorld(body, point); + } + + /// + /// Convert body absolute/world coordinates to relative/local coordinates. + /// + /// + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public Vect WorldToLocal(Vect point) + { + return NativeMethods.cpBodyWorldToLocal(body, point); + } + + /// + /// Get the velocity on a body (in world units) at a point on the body in world coordinates. + /// + /// + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public Vect GetVelocityAtWorldPoint(Vect point) + { + return NativeMethods.cpBodyGetVelocityAtWorldPoint(body, point); + } + + /// + /// Get the velocity on a body (in world units) at a point on the body in local coordinates. + /// + /// + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public Vect GetVelocityAtLocalPoint(Vect point) + { + return NativeMethods.cpBodyGetVelocityAtLocalPoint(body, point); + } + + /// + /// Get the kinetic energy of a body. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public double KineticEnergy => NativeMethods.cpBodyKineticEnergy(body); + + /// + /// Calculate the moment of inertia for a solid box centered on the body. + /// + /// + /// + /// + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public static double MomentForBox(double mass, double width, double height) + { + return NativeMethods.cpMomentForBox(mass, width, height); + } + + /// + /// Get the list of all bodies in contact with this one + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public IReadOnlyList AllContactedBodies + { + get + { + int count = NativeMethods.cpBodyGetContactedBodiesCount(body); + + if (count == 0) + return Array.Empty(); + + IntPtr ptrBodies = Marshal.AllocHGlobal(IntPtr.Size * count); + NativeMethods.cpBodyGetUserDataContactedBodies(body, ptrBodies); + + IntPtr[] userDataArray = new IntPtr[count]; + + Marshal.Copy(ptrBodies, userDataArray, 0, count); + + Marshal.FreeHGlobal(ptrBodies); + + Body[] bodies = new Body[count]; + + for (int i = 0; i < count; i++) + { + Body b = NativeInterop.FromIntPtr(userDataArray[i]); + bodies[i] = b; + } + + return bodies; + } + } + + /// + /// Check if a Body is in contact with another + /// + /// + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public bool ContactWith(Body other) + { + return NativeMethods.cpBodyContactWith(body, other.body) != 0; + } + } +} diff --git a/src/Tizen.NUI.Physics2D/src/public/chipmunk/BodyType.cs b/src/Tizen.NUI.Physics2D/src/public/chipmunk/BodyType.cs new file mode 100644 index 0000000..ebf2a93 --- /dev/null +++ b/src/Tizen.NUI.Physics2D/src/public/chipmunk/BodyType.cs @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2023 Codefoco (codefoco@codefoco.com) + * + * 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. + */ + +using System.ComponentModel; + +namespace Tizen.NUI.Physics2D.Chipmunk +{ + /// + /// Chipmunk supports three different types of bodies with unique behavioral and performance + /// characteristics. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public enum BodyType + { + /// + /// Dynamic bodies are the default body type. They react to collisions, are affected by + /// forces and gravity, and have a finite amount of mass. These are the type of bodies that + /// you want the physics engine to simulate for you. Dynamic bodies interact with all types + /// of bodies and can generate collision callbacks. + /// + Dynamic, + + /// + /// Kinematic bodies are bodies that are controlled from your code instead of from the + /// physics engine. They aren't affected by gravity and they have an infinite amount of + /// mass, so they don’t react to collisions or forces with other bodies. Kinematic bodies + /// are controlled by setting their velocity, which will cause them to move. Good examples + /// of kinematic bodies might include things like moving platforms. Objects that are + /// touching or jointed to a kinematic body are never allowed to fall asleep. + /// + Kinematic, + + /// + /// Static bodies are bodies that never (or rarely) move. Using static bodies for things + /// like terrain offers a big performance boost over other body types -- Chipmunk doesn't + /// need to check for collisions between static objects and it never needs to update their + /// collision information. Additionally, because static bodies don’t move, Chipmunk knows + /// it’s safe to let objects that are touching or jointed to them fall asleep. Generally, + /// all of your level geometry will be attached to a static body, except for things like + /// moving platforms or doors. Every space provides a built-in static body for your + /// convenience. Static bodies can be moved, but there is a performance penalty as the + /// collision information is recalculated. There is no penalty for having multiple static + /// bodies, and it can be useful in simplifying your code to allow different parts of your + /// static geometry to be initialized or moved separately. + /// + Static + } +} diff --git a/src/Tizen.NUI.Physics2D/src/public/chipmunk/BoundingBox.cs b/src/Tizen.NUI.Physics2D/src/public/chipmunk/BoundingBox.cs new file mode 100644 index 0000000..535bf4e --- /dev/null +++ b/src/Tizen.NUI.Physics2D/src/public/chipmunk/BoundingBox.cs @@ -0,0 +1,161 @@ +/* + * Copyright (c) 2023 Codefoco (codefoco@codefoco.com) + * + * 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. + */ + +using System; +using System.ComponentModel; +using System.Runtime.InteropServices; + +#pragma warning disable IDE1006 +#pragma warning disable IDE0032 + +namespace Tizen.NUI.Physics2D.Chipmunk +{ + /// + /// Chipmunk's axis-aligned 2D bounding box type. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + [StructLayout(LayoutKind.Sequential)] + public struct BoundingBox : IEquatable + { + private double left; + private double bottom; + private double right; + private double top; + + /// + /// Create a bounding box with the given coordinates. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public BoundingBox(double left, double bottom, double right, double top) + { + this.left = left; + this.bottom = bottom; + this.right = right; + this.top = top; + } + + /// + /// Left value of bounding box. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public double Left { get => left; set => left = value; } + + /// + /// Bottom value of bouding box. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public double Bottom { get => bottom; set => bottom = value; } + + /// + /// Right value of bouding box. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public double Right { get => right; set => right = value; } + + /// + /// Top value of bouding box. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public double Top { get => top; set => top = value; } + + /// + /// Return true if the dimensions of both bounding boxes are equal to another (within + /// distance of each other.) + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public bool Equals(BoundingBox other) + { + return Math.Abs(left - other.left) < float.Epsilon && + Math.Abs(bottom - other.bottom) < float.Epsilon && + Math.Abs(right - other.right) < float.Epsilon && + Math.Abs(top - other.top) < float.Epsilon; + } + + /// + /// Return true if the given object is reference-equal. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public override bool Equals(object obj) + { + var bb = obj as BoundingBox?; + if (bb == null) + { + return false; + } + + return this == bb.Value; + } + + /// + /// Get the bounding box hash code. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public override int GetHashCode() + { + var hashCode = -1064806749; + +#pragma warning disable RECS0025 // Non-readonly field referenced in 'GetHashCode()' + hashCode = hashCode * -1521134295 + left.GetHashCode(); + hashCode = hashCode * -1521134295 + bottom.GetHashCode(); + hashCode = hashCode * -1521134295 + right.GetHashCode(); + hashCode = hashCode * -1521134295 + top.GetHashCode(); +#pragma warning restore RECS0025 // Non-readonly field referenced in 'GetHashCode()' + + return hashCode; + } + + /// + /// Return a string displaying coordinates formatted like (left, bottom, right, top). + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public override string ToString() + { + return $"({left},{bottom},{right},{top})"; + } + + /// + /// Return true if the dimensions of both bounding boxes are within + /// of each other. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public static bool operator ==(BoundingBox left, BoundingBox right) + { + return left.Equals(right); + } + + /// + /// Return true if the dimensions of both bounding boxes are not within + /// of each other. + /// + /// + /// + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public static bool operator !=(BoundingBox left, BoundingBox right) + { + return !(left == right); + } + } +} + +#pragma warning restore IDE1006 +#pragma warning restore IDE0032 diff --git a/src/Tizen.NUI.Physics2D/src/public/chipmunk/CollisionHandler.cs b/src/Tizen.NUI.Physics2D/src/public/chipmunk/CollisionHandler.cs new file mode 100644 index 0000000..c325a6a --- /dev/null +++ b/src/Tizen.NUI.Physics2D/src/public/chipmunk/CollisionHandler.cs @@ -0,0 +1,341 @@ +/* + * Copyright (c) 2023 Codefoco (codefoco@codefoco.com) + * + * 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. + */ + +using System; +using System.ComponentModel; +using System.Diagnostics; +using cpArbiter = System.IntPtr; +using cpBool = System.Byte; +using cpCollisionHandlerPointer = System.IntPtr; +using cpSpace = System.IntPtr; +using voidptr_t = System.IntPtr; + +#if __IOS__ || __TVOS__ || __WATCHOS__ || __MACCATALYST__ +using ObjCRuntime; +#endif + +namespace Tizen.NUI.Physics2D.Chipmunk +{ + /// + /// A collision handler is a set of 4 function callbacks for the different collision events that + /// Chipmunk recognizes. Collision callbacks are closely associated with + /// objects. You should familiarize yourself with those as well. Note #1: Shapes tagged as + /// sensors ( == true) never generate collisions that get processed, + /// so collisions between sensor shapes and other shapes will never call the post_solve() + /// callback. They still generate begin() and separate() callbacks, and the pre_solve() callback + /// is also called every frame even though there is no collision response. Note #2: pre_solve() + /// callbacks are called before the sleeping algorithm runs. If an object falls asleep, its + /// post_solve() callback won’t be called until it’s re-awoken. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public sealed class CollisionHandler + { + private readonly cpCollisionHandlerPointer handle; + + private static CollisionBeginFunction beginCallback = CollisionBeginFunctionCallback; + private static CollisionPreSolveFunction preSolveCallback = CollisionPreSolveFunctionCallback; + private static CollisionPostSolveFunction postSolveCallback = CollisionPostSolveFunctionCallback; + private static CollisionSeparateFunction separeteCallback = CollisionSeparateFunctionCallback; + + private static IntPtr DefaultBeginFunction; + private static IntPtr DefaultPreSolveFunction; + private static IntPtr DefaultPostSolveFunction; + private static IntPtr DefaultSeparateFunction; + + private CollisionHandler(cpCollisionHandlerPointer collisionHandle, ref cpCollisionHandler handler) + { + handle = collisionHandle; + + IntPtr data = NativeInterop.RegisterHandle(this); + + handler.userData = data; + + long typeA = (long)handler.typeA.ToUInt64(); + long typeB = (long)handler.typeB.ToUInt64(); + + TypeA = unchecked((int)typeA); + TypeB = unchecked((int)typeB); + + cpCollisionHandler.ToPointer(handler, handle); + } + + internal static CollisionHandler GetOrCreate(cpCollisionHandlerPointer collisionHandle) + { + Debug.Assert(collisionHandle != IntPtr.Zero, "CollisionHandle cannot be zero"); + + var handler = cpCollisionHandler.FromHandle(collisionHandle); + + if (handler.userData != IntPtr.Zero) + { + return NativeInterop.FromIntPtr(handler.userData); + } + + EnsureDefaultCallbackValues(handler); + + return new CollisionHandler(collisionHandle, ref handler); + } + + private static void EnsureDefaultCallbackValues(cpCollisionHandler handler) + { + if (DefaultBeginFunction != IntPtr.Zero) + return; + + DefaultBeginFunction = handler.beginFunction; + DefaultPreSolveFunction = handler.preSolveFunction; + DefaultPostSolveFunction = handler.postSolveFunction; + DefaultSeparateFunction = handler.separateFunction; + } + + private Action begin; + + /// + /// This function is called when two shapes with types that match this collision handler begin colliding + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public Action Begin + { + set + { + begin = value; + + var handler = cpCollisionHandler.FromHandle(handle); + + IntPtr callbackPointer; + + if (value == null) + { + callbackPointer = DefaultBeginFunction; + } + else + { + callbackPointer = beginCallback.ToFunctionPointer(); + } + + handler.beginFunction = callbackPointer; + + cpCollisionHandler.ToPointer(handler, handle); + } + get => begin; + } + + private Func preSolve; + + /// + /// This function is called each step when two shapes with types that match this collision + /// handler are colliding. It's called before the collision solver runs so that you can + /// affect a collision's outcome. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public Func PreSolve + { + set + { + preSolve = value; + var handler = cpCollisionHandler.FromHandle(handle); + IntPtr callbackPointer; + + if (value == null) + { + callbackPointer = DefaultPreSolveFunction; + } + else + { + callbackPointer = preSolveCallback.ToFunctionPointer(); + } + + handler.preSolveFunction = callbackPointer; + cpCollisionHandler.ToPointer(handler, handle); + } + get => preSolve; + } + + private Action postSolve; + + /// + /// This function is called each step when two shapes with types that match this collision + /// handler are colliding. It's called after the collision solver runs so that you can read + /// back information about the collision to trigger events in your game. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public Action PostSolve + { + set + { + postSolve = value; + var handler = cpCollisionHandler.FromHandle(handle); + IntPtr callbackPointer; + + if (value == null) + { + callbackPointer = DefaultPostSolveFunction; + } + else + { + callbackPointer = postSolveCallback.ToFunctionPointer(); + } + + handler.postSolveFunction = callbackPointer; + cpCollisionHandler.ToPointer(handler, handle); + } + get => postSolve; + } + + private Action separate; + + /// + /// This function is called when two shapes with types that match this collision handler + /// stop colliding. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public Action Separate + { + set + { + separate = value; + var handler = cpCollisionHandler.FromHandle(handle); + IntPtr callbackPointer; + + if (value == null) + { + callbackPointer = DefaultSeparateFunction; + } + else + { + callbackPointer = separeteCallback.ToFunctionPointer(); + } + + handler.separateFunction = callbackPointer; + cpCollisionHandler.ToPointer(handler, handle); + } + get => separate; + } + + /// + /// User definable context pointer that is passed to all of the collision handler functions. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public object Data { get; set; } + + /// + /// In the collision handler callback, the shape with this type will be the first argument. + /// Read only. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public int TypeA { get; } + + /// + /// In the collision handler callback, the shape with this type will be the second argument. + /// Read only. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public int TypeB { get; } + +#if __IOS__ || __TVOS__ || __WATCHOS__ || __MACCATALYST__ +#pragma warning disable CA1416 // Validate platform compatibility + [MonoPInvokeCallback(typeof(CollisionBeginFunction))] +#pragma warning restore CA1416 // Validate platform compatibility +#endif + private static void CollisionBeginFunctionCallback(cpArbiter arbiterHandle, cpSpace spaceHandle, voidptr_t userData) + { + var arbiter = new Arbiter(arbiterHandle); + var space = Space.FromHandle(spaceHandle); + + var handler = NativeInterop.FromIntPtr(userData); + var begin = handler.Begin; + + if (begin == null) + { + return; + } + + begin(arbiter, space, handler.Data); + } + +#if __IOS__ || __TVOS__ || __WATCHOS__ || __MACCATALYST__ +#pragma warning disable CA1416 // Validate platform compatibility + [MonoPInvokeCallback(typeof(CollisionPreSolveFunction))] +#pragma warning restore CA1416 // Validate platform compatibility +#endif + private static cpBool CollisionPreSolveFunctionCallback(cpArbiter arbiterHandle, cpSpace spaceHandle, voidptr_t userData) + { + var arbiter = new Arbiter(arbiterHandle); + var space = Space.FromHandle(spaceHandle); + + var handler = NativeInterop.FromIntPtr(userData); + var preSolve = handler.PreSolve; + + if (preSolve == null) + { + return 1; + } + + if (preSolve(arbiter, space, handler.Data)) + { + return 1; + } + + return 0; + } + +#if __IOS__ || __TVOS__ || __WATCHOS__ || __MACCATALYST__ +#pragma warning disable CA1416 // Validate platform compatibility + [MonoPInvokeCallback(typeof(CollisionPostSolveFunction))] +#pragma warning restore CA1416 // Validate platform compatibility +#endif + private static void CollisionPostSolveFunctionCallback(cpArbiter arbiterHandle, cpSpace spaceHandle, voidptr_t userData) + { + var arbiter = new Arbiter(arbiterHandle); + var space = Space.FromHandle(spaceHandle); + + var handler = NativeInterop.FromIntPtr(userData); + var postSolve = handler.PostSolve; + + if (postSolve == null) + { + return; + } + + postSolve(arbiter, space, handler.Data); + } + +#if __IOS__ || __TVOS__ || __WATCHOS__ || __MACCATALYST__ +#pragma warning disable CA1416 // Validate platform compatibility + [MonoPInvokeCallback(typeof(CollisionSeparateFunction))] +#pragma warning restore CA1416 // Validate platform compatibility +#endif + private static void CollisionSeparateFunctionCallback(cpArbiter arbiterHandle, cpSpace spaceHandle, voidptr_t userData) + { + var arbiter = new Arbiter(arbiterHandle); + var space = Space.FromHandle(spaceHandle); + + var handler = NativeInterop.FromIntPtr(userData); + var separate = handler.Separate; + + if (separate == null) + { + return; + } + + separate(arbiter, space, handler.Data); + } + } +} diff --git a/src/Tizen.NUI.Physics2D/src/public/chipmunk/Constraints/Constraint.cs b/src/Tizen.NUI.Physics2D/src/public/chipmunk/Constraints/Constraint.cs new file mode 100644 index 0000000..bf57b7a --- /dev/null +++ b/src/Tizen.NUI.Physics2D/src/public/chipmunk/Constraints/Constraint.cs @@ -0,0 +1,301 @@ +/* + * Copyright (c) 2023 Codefoco (codefoco@codefoco.com) + * + * 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. + */ + +using System; +using System.Diagnostics; +using System.ComponentModel; +using cpBody = System.IntPtr; +using cpConstraint = System.IntPtr; +using cpDataPointer = System.IntPtr; +using cpSpace = System.IntPtr; + +#if __IOS__ || __TVOS__ || __WATCHOS__ || __MACCATALYST__ +using ObjCRuntime; +#endif + + +namespace Tizen.NUI.Physics2D.Chipmunk +{ + /// + /// Base class of all constraints. + /// You usually don’t want to create instances of this class directly, but instead use one of + /// the specific constraints such as the . + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public abstract class Constraint : IDisposable + { +#pragma warning disable IDE0032 + cpConstraint constraint; +#pragma warning restore IDE0032 + + /// + /// Construct a constraint with the given native handle. + /// + /// + internal protected Constraint(cpConstraint handle) + { + constraint = handle; + RegisterUserData(); + } + + /// + /// Native handle to constraint. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public cpConstraint Handle => constraint; + + /// + /// Register managed object to native user data. + /// + private void RegisterUserData() + { + cpDataPointer pointer = NativeInterop.RegisterHandle(this); + NativeMethods.cpConstraintSetUserData(constraint, pointer); + } + + void ReleaseUserData() + { + cpDataPointer pointer = NativeMethods.cpConstraintGetUserData(constraint); + NativeInterop.ReleaseHandle(pointer); + } + + /// + /// Get a Constraint object from a native handle. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public static Constraint FromHandle(cpConstraint constraint) + { + cpDataPointer handle = NativeMethods.cpConstraintGetUserData(constraint); + return NativeInterop.FromIntPtr(handle); + } + + /// + /// Dispose the constraint. + /// + protected virtual void Dispose(bool dispose) + { + if (!dispose) + { + Debug.WriteLine("Disposing constraint {0} on finalizer... (consider Dispose explicitly)", constraint); + } + + Free(); + } + + /// + /// Destroy and free the constraint. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public void Free() + { + ReleaseUserData(); + NativeMethods.cpConstraintFree(constraint); + } + + /// + /// Destroy the constraint + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + /// + /// Get the cpSpace this constraint is added to. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public Space Space + { + get + { + cpSpace space = NativeMethods.cpConstraintGetSpace(constraint); + return Space.FromHandleSafe(space); + } + } + + /// + /// Get the first body the constraint is attached to. + /// + public Body BodyA + { + get + { + cpBody body = NativeMethods.cpConstraintGetBodyA(constraint); + return Body.FromHandleSafe(body); + } + } + + /// + /// Get the second body the constraint is attached to. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public Body BodyB + { + get + { + cpBody body = NativeMethods.cpConstraintGetBodyB(constraint); + return Body.FromHandleSafe(body); + } + } + + /// ; + /// The maximum force that this constraint is allowed to use. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public double MaxForce + { + get => NativeMethods.cpConstraintGetMaxForce(constraint); + set => NativeMethods.cpConstraintSetMaxForce(constraint, value); + } + + /// + /// Rate at which joint error is corrected. + /// Defaults to pow(1.0 - 0.1, 60.0) meaning that it will + /// correct 10% of the error every 1/60th of a second. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public double ErrorBias + { + get => NativeMethods.cpConstraintGetErrorBias(constraint); + set => NativeMethods.cpConstraintSetErrorBias(constraint, value); + } + + + /// + /// The maximum rate at which joint error is corrected. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public double MaxBias + { + get => NativeMethods.cpConstraintGetMaxBias(constraint); + set => NativeMethods.cpConstraintSetMaxBias(constraint, value); + } + + /// + /// Whether the two bodies connected by the constraint are allowed to collide or not. + /// + /// When two bodies collide, Chipmunk ignores the collisions if this property is set to + /// False on any constraint that connects the two bodies. Defaults to True. This can be + /// used to create a chain that self-collides, but adjacent links in the chain do not collide. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public bool CollideBodies + { + get => NativeMethods.cpConstraintGetCollideBodies(constraint) != 0; + set => NativeMethods.cpConstraintSetCollideBodies(constraint, value ? (byte)1 : (byte)0); + } + + private static ConstraintSolveFunction preSolveFunctionCallback = ConstraintPreSolveFunctionCallback; + private static ConstraintSolveFunction postSolveFunctionCallback = ConstraintPostSolveFunctionCallback; + + private Action preSolve; + private Action postSolve; + + /// + /// Pre-solve function that is called before the solver runs. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public Action PreSolve + { + get => preSolve; + set + { + preSolve = value; + + IntPtr callbackPointer; + + if (value == null) + callbackPointer = IntPtr.Zero; + else + callbackPointer = preSolveFunctionCallback.ToFunctionPointer(); + + NativeMethods.cpConstraintSetPreSolveFunc(constraint, callbackPointer); + } + } + + /// + /// Post-solve function that is called after the solver runs. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public Action PostSolve + { + get => postSolve; + set + { + postSolve = value; + + IntPtr callbackPointer; + + if (value == null) + callbackPointer = IntPtr.Zero; + else + callbackPointer = postSolveFunctionCallback.ToFunctionPointer(); + + NativeMethods.cpConstraintSetPostSolveFunc(constraint, callbackPointer); + } + } + +#if __IOS__ || __TVOS__ || __WATCHOS__ || __MACCATALYST__ +#pragma warning disable CA1416 // Validate platform compatibility + [MonoPInvokeCallback(typeof(ConstraintSolveFunction))] +#pragma warning restore CA1416 // Validate platform compatibility +#endif + private static void ConstraintPreSolveFunctionCallback(cpConstraint constraintHandle, cpSpace spaceHandle) + { + var constraint = Constraint.FromHandle(constraintHandle); + var space = Space.FromHandle(spaceHandle); + + Action preSolve = constraint.PreSolve; + + preSolve(constraint, space); + } + +#if __IOS__ || __TVOS__ || __WATCHOS__ || __MACCATALYST__ +#pragma warning disable CA1416 // Validate platform compatibility + [MonoPInvokeCallback(typeof(ConstraintSolveFunction))] +#pragma warning restore CA1416 // Validate platform compatibility +#endif + private static void ConstraintPostSolveFunctionCallback(cpConstraint constraintHandle, cpSpace spaceHandle) + { + var constraint = Constraint.FromHandle(constraintHandle); + var space = Space.FromHandle(spaceHandle); + + Action postSolve = constraint.PostSolve; + + postSolve(constraint, space); + } + + /// + /// The user-definable data pointer for this constraint. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public object Data { get; set; } + + /// + /// Get the last impulse applied by this constraint. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public double Impulse => NativeMethods.cpConstraintGetImpulse(constraint); + } +} diff --git a/src/Tizen.NUI.Physics2D/src/public/chipmunk/Constraints/DampedRotarySpring.cs b/src/Tizen.NUI.Physics2D/src/public/chipmunk/Constraints/DampedRotarySpring.cs new file mode 100644 index 0000000..44ad728 --- /dev/null +++ b/src/Tizen.NUI.Physics2D/src/public/chipmunk/Constraints/DampedRotarySpring.cs @@ -0,0 +1,143 @@ +/* + * Copyright (c) 2023 Codefoco (codefoco@codefoco.com) + * + * 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. + */ + +using System; +using System.ComponentModel; + +using cpConstraint = System.IntPtr; + + +#if __IOS__ || __TVOS__ || __WATCHOS__ || __MACCATALYST__ +using ObjCRuntime; +#endif + +namespace Tizen.NUI.Physics2D.Chipmunk +{ + /// + /// DampedRotarySpring works like , but in an angular fashion. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public class DampedRotarySpring : Constraint + { + /// + /// Check if a constraint is a . + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public static bool IsDampedRotarySpring(Constraint constraint) => NativeMethods.cpConstraintIsDampedRotarySpring(constraint.Handle) != 0; + + /// + /// Create a damped rotary spring. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public DampedRotarySpring( + Body bodyA, + Body bodyB, + double restAngle, + double stiffness, + double damping) + : base( + NativeMethods.cpDampedRotarySpringNew( + bodyA.Handle, + bodyB.Handle, + restAngle, + stiffness, + damping)) + { + originalTorqueCallbackPointer = NativeMethods.cpDampedRotarySpringGetSpringTorqueFunc(Handle); + } + +#if __IOS__ || __TVOS__ || __WATCHOS__ || __MACCATALYST__ +#pragma warning disable CA1416 // Validate platform compatibility + [MonoPInvokeCallback(typeof(DampedRotarySpringTorqueFunction))] +#pragma warning restore CA1416 // Validate platform compatibility +#endif + private static double DampedRotarySpringTorqueCallback(cpConstraint springHandle, double relativeAngle) + { + var constraint = (DampedRotarySpring)FromHandle(springHandle); + + Func dampedRotarySpringTorqueFunction = constraint.TorqueFunction; + + return dampedRotarySpringTorqueFunction(constraint, relativeAngle); + } + + private static DampedRotarySpringTorqueFunction DampedRotarySpringForceCallback = DampedRotarySpringTorqueCallback; + + /// + /// The rest angle of the spring. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public double RestAngle + { + get => NativeMethods.cpDampedRotarySpringGetRestAngle(Handle); + set => NativeMethods.cpDampedRotarySpringSetRestAngle(Handle, value); + } + + /// + /// The stiffness of the spring in force/distance. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public double Stiffness + { + get => NativeMethods.cpDampedRotarySpringGetStiffness(Handle); + set => NativeMethods.cpDampedRotarySpringSetStiffness(Handle, value); + } + + /// + /// The damping of the spring. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public double Damping + { + get => NativeMethods.cpDampedRotarySpringGetDamping(Handle); + set => NativeMethods.cpDampedRotarySpringSetDamping(Handle, value); + } + + private Func torqueFunction; + private IntPtr originalTorqueCallbackPointer; + + /// + /// Damped rotary spring torque custom function callback. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public Func TorqueFunction + { + get => torqueFunction; + set + { + torqueFunction = value; + + IntPtr callbackPointer; + + if (value == null) + { + callbackPointer = originalTorqueCallbackPointer; + } + else + { + callbackPointer = DampedRotarySpringForceCallback.ToFunctionPointer(); + } + + NativeMethods.cpDampedRotarySpringSetSpringTorqueFunc(Handle, callbackPointer); + } + } + } +} diff --git a/src/Tizen.NUI.Physics2D/src/public/chipmunk/Constraints/DampedSpring.cs b/src/Tizen.NUI.Physics2D/src/public/chipmunk/Constraints/DampedSpring.cs new file mode 100644 index 0000000..9ffa323 --- /dev/null +++ b/src/Tizen.NUI.Physics2D/src/public/chipmunk/Constraints/DampedSpring.cs @@ -0,0 +1,175 @@ +/* + * Copyright (c) 2023 Codefoco (codefoco@codefoco.com) + * + * 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. + */ + +using System; +using System.ComponentModel; + +using cpConstraint = System.IntPtr; + + +#if __IOS__ || __TVOS__ || __WATCHOS__ || __MACCATALYST__ +using ObjCRuntime; +#endif + +namespace Tizen.NUI.Physics2D.Chipmunk +{ + /// + /// is a damped spring. + /// The spring allows you to define the rest length, stiffness and damping. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public class DampedSpring : Constraint + { + /// + /// Check if a constraint is a . + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public static bool IsDampedSpring(Constraint constraint) => NativeMethods.cpConstraintIsDampedSpring(constraint.Handle) != 0; + + /// + /// Defined much like a slide joint. + /// + /// The first connected body. + /// The second connected body. + /// Anchor point a, relative to body a. + /// Anchor point b, relative to body b. + /// The distance the spring wants to be. + /// The spring constant (Young’s modulus). + /// How soft to make the damping of the spring. + [EditorBrowsable(EditorBrowsableState.Never)] + public DampedSpring( + Body bodyA, + Body bodyB, + Vect anchorA, + Vect anchorB, + double restLength, + double stiffness, + double damping) + : base(NativeMethods.cpDampedSpringNew( + bodyA.Handle, + bodyB.Handle, + anchorA, + anchorB, + restLength, + stiffness, + damping)) + { + originalForceCallbackPointer = NativeMethods.cpDampedSpringGetSpringForceFunc(Handle); + } + +#if __IOS__ || __TVOS__ || __WATCHOS__ || __MACCATALYST__ +#pragma warning disable CA1416 // Validate platform compatibility + [MonoPInvokeCallback(typeof(DampedSpringForceFunction))] +#pragma warning restore CA1416 // Validate platform compatibility +#endif + private static double DampedSpringForceCallback(cpConstraint springHandle, double distance) + { + var constraint = (DampedSpring)Constraint.FromHandle(springHandle); + + Func dampedSpringForceFunction = constraint.forceFunction; + + return dampedSpringForceFunction(constraint, distance); + } + + private static DampedSpringForceFunction dampedSpringForceCallback = DampedSpringForceCallback; + + /// + /// The location of the first anchor relative to the first body. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public Vect AnchorA + { + get => NativeMethods.cpDampedSpringGetAnchorA(Handle); + set => NativeMethods.cpDampedSpringSetAnchorA(Handle, value); + } + + /// + /// The location of the second anchor relative to the second body. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public Vect AnchorB + { + get => NativeMethods.cpDampedSpringGetAnchorB(Handle); + set => NativeMethods.cpDampedSpringSetAnchorB(Handle, value); + } + + /// + /// The rest length of the spring. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public double RestLength + { + get => NativeMethods.cpDampedSpringGetRestLength(Handle); + set => NativeMethods.cpDampedSpringSetRestLength(Handle, value); + } + + /// + /// The stiffness of the spring in force/distance. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public double Stiffness + { + get => NativeMethods.cpDampedSpringGetStiffness(Handle); + set => NativeMethods.cpDampedSpringSetStiffness(Handle, value); + } + + /// + /// The damping of the spring. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public double Damping + { + get => NativeMethods.cpDampedSpringGetDamping(Handle); + set => NativeMethods.cpDampedSpringSetDamping(Handle, value); + } + + private Func forceFunction; + + private IntPtr originalForceCallbackPointer; + + /// + /// Damped spring force custom function callback. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public Func ForceFunction + { + get => forceFunction; + set + { + forceFunction = value; + + IntPtr callbackPointer; + + if (value == null) + { + callbackPointer = originalForceCallbackPointer; + } + else + { + callbackPointer = dampedSpringForceCallback.ToFunctionPointer(); + } + + NativeMethods.cpDampedSpringSetSpringForceFunc(Handle, callbackPointer); + } + } + } +} diff --git a/src/Tizen.NUI.Physics2D/src/public/chipmunk/Constraints/GearJoint.cs b/src/Tizen.NUI.Physics2D/src/public/chipmunk/Constraints/GearJoint.cs new file mode 100644 index 0000000..601342e --- /dev/null +++ b/src/Tizen.NUI.Physics2D/src/public/chipmunk/Constraints/GearJoint.cs @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2023 Codefoco (codefoco@codefoco.com) + * + * 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. + */ + +using System.ComponentModel; + +namespace Tizen.NUI.Physics2D.Chipmunk +{ + /// + /// keeps the angular velocity ratio of a pair of bodies constant. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public class GearJoint : Constraint + { + /// + /// Check if a constraint is a . + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public static bool IsGearJoint(Constraint constraint) => NativeMethods.cpConstraintIsGearJoint(constraint.Handle) != 0; + + /// + /// Keeps the angular velocity ratio of a pair of bodies constant. + /// + /// The first connected body. + /// The second connected body. + /// The seconded connected body. + /// + /// Measured in absolute terms. It is currently not possible to set + /// the ratio in relation to a third body’s angular velocity. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public GearJoint(Body bodyA, Body bodyB, double phase, double ratio) : + base(NativeMethods.cpGearJointNew(bodyA.Handle, bodyB.Handle, phase, ratio)) + { + } + + /// + /// The phase offset of the gears. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public double Phase + { + get => NativeMethods.cpGearJointGetPhase(Handle); + set => NativeMethods.cpGearJointSetPhase(Handle, value); + } + + /// + /// The ratio of a gear joint. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public double Ratio + { + get => NativeMethods.cpGearJointGetRatio(Handle); + set => NativeMethods.cpGearJointSetRatio(Handle, value); + } + } +} diff --git a/src/Tizen.NUI.Physics2D/src/public/chipmunk/Constraints/GrooveJoint.cs b/src/Tizen.NUI.Physics2D/src/public/chipmunk/Constraints/GrooveJoint.cs new file mode 100644 index 0000000..e295b31 --- /dev/null +++ b/src/Tizen.NUI.Physics2D/src/public/chipmunk/Constraints/GrooveJoint.cs @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2023 Codefoco (codefoco@codefoco.com) + * + * 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. + */ + +using System.ComponentModel; + +namespace Tizen.NUI.Physics2D.Chipmunk +{ + /// + /// is similar to a , but with a linear slide. + /// One of the anchor points is a line segment that the pivot can slide on instead of being fixed. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public class GrooveJoint : Constraint + { + /// + /// Check if a constraint is a . + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public static bool IsGrooveJoint(Constraint constraint) => NativeMethods.cpConstraintIsGrooveJoint(constraint.Handle) != 0; + + /// + /// Create an anchor where can rotate similar to a + /// , except it's anchored at , which is a + /// point that can slide between and . + /// + /// The first connected body. + /// The second connected body. + /// + /// The start of the groove on . Coordinates are local to the body. + /// + /// + /// The end of the groove on . Coordinates are local to the body. + /// + /// + /// The location of the pivot on . Coordinates are local to the + /// body. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public GrooveJoint(Body bodyA, Body bodyB, Vect grooveA, Vect grooveB, Vect anchorB) + : base(NativeMethods.cpGrooveJointNew(bodyA.Handle, bodyB.Handle, grooveA, grooveB, anchorB)) + { + } + + /// + /// The first endpoint of the groove relative to the first body. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public Vect GrooveA + { + get => NativeMethods.cpGrooveJointGetGrooveA(Handle); + set => NativeMethods.cpGrooveJointSetGrooveA(Handle, value); + } + + /// + /// The second endpoint of the groove relative to the first body. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public Vect GrooveB + { + get => NativeMethods.cpGrooveJointGetGrooveB(Handle); + set => NativeMethods.cpGrooveJointSetGrooveB(Handle, value); + } + + /// + /// The location of the second anchor relative to the second body. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public Vect AnchorB + { + get => NativeMethods.cpGrooveJointGetAnchorB(Handle); + set => NativeMethods.cpGrooveJointSetAnchorB(Handle, value); + } + } +} diff --git a/src/Tizen.NUI.Physics2D/src/public/chipmunk/Constraints/PinJoint.cs b/src/Tizen.NUI.Physics2D/src/public/chipmunk/Constraints/PinJoint.cs new file mode 100644 index 0000000..f0f9e94 --- /dev/null +++ b/src/Tizen.NUI.Physics2D/src/public/chipmunk/Constraints/PinJoint.cs @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2023 Codefoco (codefoco@codefoco.com) + * + * 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. + */ + +using System.ComponentModel; + +namespace Tizen.NUI.Physics2D.Chipmunk +{ + /// + /// links shapes with a solid bar or pin. Keeps the anchor points at a + /// set distance from one another. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public class PinJoint : Constraint + { + /// + /// Check if a constraint is a . + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public static bool IsPinJoint(Constraint constraint) => NativeMethods.cpConstraintIsPinJoint(constraint.Handle) != 0; + + /// + /// The distance between the two anchor points is measured when the joint is created. If you + /// want to set a specific distance, use the setter function to override it. + /// + /// One of the two bodies to connect. + /// One of the two bodies to connect. + /// The anchor point for . + /// The anchor point for . + [EditorBrowsable(EditorBrowsableState.Never)] + public PinJoint(Body bodyA, Body bodyB, Vect anchorA, Vect anchorB) + : base(NativeMethods.cpPinJointNew(bodyA.Handle, bodyB.Handle, anchorA, anchorB)) + { + } + + /// + /// The location of the first anchor relative to the first body. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public Vect AnchorA + { + get => NativeMethods.cpPinJointGetAnchorA(Handle); + set => NativeMethods.cpPinJointSetAnchorA(Handle, value); + } + + /// + /// The location of the second anchor relative to the second body. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public Vect AnchorB + { + get => NativeMethods.cpPinJointGetAnchorB(Handle); + set => NativeMethods.cpPinJointSetAnchorB(Handle, value); + } + + /// + /// The distance the joint will maintain between the two anchors. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public double Distance + { + get => NativeMethods.cpPinJointGetDist(Handle); + set => NativeMethods.cpPinJointSetDist(Handle, value); + } + } +} diff --git a/src/Tizen.NUI.Physics2D/src/public/chipmunk/Constraints/PivotJoint.cs b/src/Tizen.NUI.Physics2D/src/public/chipmunk/Constraints/PivotJoint.cs new file mode 100644 index 0000000..de7a9bd --- /dev/null +++ b/src/Tizen.NUI.Physics2D/src/public/chipmunk/Constraints/PivotJoint.cs @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2023 Codefoco (codefoco@codefoco.com) + * + * 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. + */ + +using System.ComponentModel; + +namespace Tizen.NUI.Physics2D.Chipmunk +{ + /// + /// acts like a swivel, allowing two objects to pivot about a single + /// point. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public class PivotJoint : Constraint + { + /// + /// Check if a constraint is a . + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public static bool IsPivotJoint(Constraint constraint) => NativeMethods.cpConstraintIsPivotJoint(constraint.Handle) != 0; + + /// + /// Initialize a pivot joint with two anchors. Since the anchors are provided in world + /// coordinates, the bodies must already be correctly positioned. The joint is fixed as soon + /// as the containing space is simulated. + /// + /// One of the two bodies to connect. + /// One of the two bodies to connect. + /// + /// The location of one of the anchors, specified in world coordinates. + /// + /// + /// The location of one of the anchors, specified in world coordinates. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public PivotJoint(Body bodyA, Body bodyB, Vect anchorA, Vect anchorB) + : base(NativeMethods.cpPivotJointNew2(bodyA.Handle, bodyB.Handle, anchorA, anchorB)) + { + } + + /// + /// Initialize a pivot joint with one anchor. Since the pivot is provided in world + /// coordinates, the bodies must already be correctly positioned. + /// + /// One of the two bodies to connect. + /// One of the two bodies to connect. + /// The location of the pivot, specified in world coordinates. + [EditorBrowsable(EditorBrowsableState.Never)] + public PivotJoint(Body bodyA, Body bodyB, Vect anchor) : + base(NativeMethods.cpPivotJointNew(bodyA.Handle, bodyB.Handle, anchor)) + { + + } + + /// + /// The location of the first anchor relative to the first body. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public Vect AnchorA + { + get => NativeMethods.cpPivotJointGetAnchorA(Handle); + set => NativeMethods.cpPivotJointSetAnchorA(Handle, value); + } + + /// + /// The location of the second anchor relative to the second body. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public Vect AnchorB + { + get => NativeMethods.cpPivotJointGetAnchorB(Handle); + set => NativeMethods.cpPivotJointSetAnchorB(Handle, value); + } + + } +} diff --git a/src/Tizen.NUI.Physics2D/src/public/chipmunk/Constraints/RatchetJoint.cs b/src/Tizen.NUI.Physics2D/src/public/chipmunk/Constraints/RatchetJoint.cs new file mode 100644 index 0000000..4c368ac --- /dev/null +++ b/src/Tizen.NUI.Physics2D/src/public/chipmunk/Constraints/RatchetJoint.cs @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2023 Codefoco (codefoco@codefoco.com) + * + * 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. + */ + +using System.ComponentModel; + +namespace Tizen.NUI.Physics2D.Chipmunk +{ + /// + /// is a rotary ratchet, which works like a socket wrench. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public class RatchetJoint : Constraint + { + /// + /// Check if a constraint is a . + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public static bool IsRatchetJoint(Constraint constraint) => NativeMethods.cpConstraintIsRatchetJoint(constraint.Handle) != 0; + + /// + /// Works like a socket wrench. + /// + /// One of the two bodies to connect. + /// One of the two bodies to connect. + /// + /// The initial offset to use when deciding where the ratchet angles are. + /// + /// + /// The distance between "clicks" (following the socket wrench analogy). + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public RatchetJoint(Body bodyA, Body bodyB, double phase, double ratchet) + : base(NativeMethods.cpRatchetJointNew(bodyA.Handle, bodyB.Handle, phase, ratchet)) + { + } + + /// + /// The angle of the current ratchet tooth. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public double Angle + { + get => NativeMethods.cpRatchetJointGetAngle(Handle); + set => NativeMethods.cpRatchetJointSetAngle(Handle, value); + } + + /// + /// The phase offset of the ratchet. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public double Phase + { + get => NativeMethods.cpRatchetJointGetPhase(Handle); + set => NativeMethods.cpRatchetJointSetPhase(Handle, value); + } + + /// + /// The angular distance of each ratchet. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public double Rachet + { + get => NativeMethods.cpRatchetJointGetRatchet(Handle); + set => NativeMethods.cpRatchetJointSetRatchet(Handle, value); + } + } +} diff --git a/src/Tizen.NUI.Physics2D/src/public/chipmunk/Constraints/RotaryLimitJoint.cs b/src/Tizen.NUI.Physics2D/src/public/chipmunk/Constraints/RotaryLimitJoint.cs new file mode 100644 index 0000000..16b6fa1 --- /dev/null +++ b/src/Tizen.NUI.Physics2D/src/public/chipmunk/Constraints/RotaryLimitJoint.cs @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2023 Codefoco (codefoco@codefoco.com) + * + * 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. + */ + +using System.ComponentModel; + +namespace Tizen.NUI.Physics2D.Chipmunk +{ + /// + /// constrains the relative rotations of two bodies. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public class RotaryLimitJoint : Constraint + { + /// + /// Check if a constraint is a . + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public static bool IsRotaryLimitJoint(Constraint constraint) => NativeMethods.cpConstraintIsRotaryLimitJoint(constraint.Handle) != 0; + + /// + /// Constrains the relative rotations of two bodies. + /// + /// + /// + /// + /// The minimum angular limit in radians. May be greater than 1 backwards revolution. + /// + /// + /// The maximum angular limit in radians. May be greater than 1 revolution. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public RotaryLimitJoint(Body bodyA, Body bodyB, double mininum, double maximum) + : base(NativeMethods.cpRotaryLimitJointNew(bodyA.Handle, bodyB.Handle, mininum, maximum)) + { + } + + /// + /// The minimum distance the joint will maintain between the two anchors. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public double Minimum + { + get => NativeMethods.cpRotaryLimitJointGetMin(Handle); + set => NativeMethods.cpRotaryLimitJointSetMin(Handle, value); + } + + /// + /// The maximum distance the joint will maintain between the two anchors. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public double Maximum + { + get => NativeMethods.cpRotaryLimitJointGetMax(Handle); + set => NativeMethods.cpRotaryLimitJointSetMax(Handle, value); + } + } +} diff --git a/src/Tizen.NUI.Physics2D/src/public/chipmunk/Constraints/SimpleMotor.cs b/src/Tizen.NUI.Physics2D/src/public/chipmunk/Constraints/SimpleMotor.cs new file mode 100644 index 0000000..a8c2d80 --- /dev/null +++ b/src/Tizen.NUI.Physics2D/src/public/chipmunk/Constraints/SimpleMotor.cs @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2023 Codefoco (codefoco@codefoco.com) + * + * 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. + */ + +using System.ComponentModel; + +namespace Tizen.NUI.Physics2D.Chipmunk +{ + /// + /// keeps the relative angular velocity constant. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public class SimpleMotor : Constraint + { + /// + /// Check if constraint is a . + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public static bool IsSimpleMotor(Constraint constraint) => NativeMethods.cpConstraintIsSimpleMotor(constraint.Handle) != 0; + + /// + /// Rotate with a constant relative angular velocity constant between two bodies. + /// + /// One of the two bodies. + /// One of the two bodies. + /// The rate of rotation. + [EditorBrowsable(EditorBrowsableState.Never)] + public SimpleMotor(Body bodyA, Body bodyB, double rate) + : base(NativeMethods.cpSimpleMotorNew(bodyA.Handle, bodyB.Handle, rate)) + { + } + + /// + /// The rate of the motor. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public double Rate + { + get => NativeMethods.cpSimpleMotorGetRate(Handle); + set => NativeMethods.cpSimpleMotorSetRate(Handle, value); + } + } +} diff --git a/src/Tizen.NUI.Physics2D/src/public/chipmunk/Constraints/SlideJoint.cs b/src/Tizen.NUI.Physics2D/src/public/chipmunk/Constraints/SlideJoint.cs new file mode 100644 index 0000000..9b4681f --- /dev/null +++ b/src/Tizen.NUI.Physics2D/src/public/chipmunk/Constraints/SlideJoint.cs @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2023 Codefoco (codefoco@codefoco.com) + * + * 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. + */ + +using System.ComponentModel; + +namespace Tizen.NUI.Physics2D.Chipmunk +{ + /// + /// is like a , but with a minimum and maximum + /// distance. A chain could be modeled using this joint. It keeps the anchor points from getting + /// too far apart, but will allow them to get closer together. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public class SlideJoint : Constraint + { + /// + /// Check if a constraint is a . + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public static bool IsSlideJoint(Constraint constraint) => NativeMethods.cpConstraintIsSlideJoint(constraint.Handle) != 0; + + /// + /// Create a slide constraint between two bodies. + /// + /// One of the two bodies to connect. + /// One of the two bodies to connect. + /// The anchor point for . + /// The anchor point for . + /// The minimum distance the anchor points can get to each other. + /// The maximum distance the anchor points can be apart. + [EditorBrowsable(EditorBrowsableState.Never)] + public SlideJoint(Body bodyA, Body bodyB, Vect anchorA, Vect anchorB, double min, double max) + : base(NativeMethods.cpSlideJointNew(bodyA.Handle, bodyB.Handle, anchorA, anchorB, min, max)) + { + } + + /// + /// The location of the first anchor relative to the first body. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public Vect AnchorA + { + get => NativeMethods.cpSlideJointGetAnchorA(Handle); + set => NativeMethods.cpSlideJointSetAnchorA(Handle, value); + } + + /// + /// The location of the second anchor relative to the second body. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public Vect AnchorB + { + get => NativeMethods.cpSlideJointGetAnchorB(Handle); + set => NativeMethods.cpSlideJointSetAnchorB(Handle, value); + } + + /// + /// The minimum distance the joint will maintain between the two anchors + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public double Minimum + { + get => NativeMethods.cpSlideJointGetMin(Handle); + set => NativeMethods.cpSlideJointSetMin(Handle, value); + } + + /// + /// The maximum distance the joint will maintain between the two anchors. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public double Maximum + { + get => NativeMethods.cpSlideJointGetMax(Handle); + set => NativeMethods.cpSlideJointSetMax(Handle, value); + } + } +} diff --git a/src/Tizen.NUI.Physics2D/src/public/chipmunk/ContactPoint.cs b/src/Tizen.NUI.Physics2D/src/public/chipmunk/ContactPoint.cs new file mode 100644 index 0000000..d1233d3 --- /dev/null +++ b/src/Tizen.NUI.Physics2D/src/public/chipmunk/ContactPoint.cs @@ -0,0 +1,174 @@ +/* + * Copyright (c) 2023 Codefoco (codefoco@codefoco.com) + * + * 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. + */ + +using System; +using System.ComponentModel; + +namespace Tizen.NUI.Physics2D.Chipmunk +{ + /// + /// Contains information about a contact point. and + /// are the contact positions on the surface of each shape. is the + /// penetration distance of the two, which is a negative value. This value is calculated as + /// dot(point2 - point1), normal) and is ignored when you set the + /// . + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public sealed class ContactPoint : IEquatable + { +#pragma warning disable IDE0032 + private readonly Vect pointA; + private readonly Vect pointB; + private readonly double distance; +#pragma warning restore IDE0032 + + /// + /// Point A in the contact point. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public Vect PointA => pointA; + + /// + /// Point B in the contact point. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public Vect PointB => pointB; + + /// + /// The penetration distance of the two shapes (as a negative value). This value is + /// calculated as dot(point2 - point1), normal) and is ignored when you set the + /// . + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public double Distance => distance; + + private ContactPoint(Vect pointA, Vect pointB, double distance) + { + this.pointA = pointA; + this.pointB = pointB; + this.distance = distance; + } + + /// + /// Returns true if neither is null and the points are within + /// distance of each other. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public bool Equals(ContactPoint other) + { + if (ReferenceEquals(other, null)) + { + return false; + } + + return other.pointA.Equals(pointA) + && other.pointB.Equals(pointB) + && Math.Abs(other.distance - distance) < float.Epsilon; + } + + + /// + /// Check if this is equal to an object. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public override bool Equals(object obj) + { + var other = obj as ContactPoint; + + if (other == null) + { + return false; + } + + return Equals(other); + } + + /// + /// Get the hash set. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public override int GetHashCode() + { + var hashCode = -1285340573; + + hashCode = hashCode * -1521134295 + pointA.GetHashCode(); + hashCode = hashCode * -1521134295 + pointB.GetHashCode(); + hashCode = hashCode * -1521134295 + distance.GetHashCode(); + + return hashCode; + } + + /// + /// Returns a string in the format of "a: {pointA}, b: {pointB}, distance: {distance}". + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public override string ToString() + { + return $"a: {pointA}, b: {pointB}, distance: {distance}"; + } + + /// + /// Returns true if both s are the same object or the dimensions + /// are within distance of each other. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public static bool operator ==(ContactPoint left, ContactPoint right) + { + if (ReferenceEquals(left, null)) + { + return ReferenceEquals(right, null); + } + + return left.Equals(right); + } + + /// + /// Returns false if both s are the same object or the dimensions + /// are within distance of each other. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public static bool operator !=(ContactPoint left, ContactPoint right) + { + return !(left == right); + } + + internal static ContactPoint Empty => new ContactPoint(Vect.Zero, Vect.Zero, 0.0); + + internal static ContactPoint FromCollidePoint(cpContactPoint contactPoint) + { + return new ContactPoint( + contactPoint.pointA, + contactPoint.pointB, + contactPoint.distance); + } + + internal cpContactPoint ToContactPoint() + { + return new cpContactPoint + { + pointA = pointA, + pointB = pointB, + distance = distance + }; + } + } +} diff --git a/src/Tizen.NUI.Physics2D/src/public/chipmunk/ContactPointSet.cs b/src/Tizen.NUI.Physics2D/src/public/chipmunk/ContactPointSet.cs new file mode 100644 index 0000000..8a623f0 --- /dev/null +++ b/src/Tizen.NUI.Physics2D/src/public/chipmunk/ContactPointSet.cs @@ -0,0 +1,178 @@ +/* + * Copyright (c) 2023 Codefoco (codefoco@codefoco.com) + * + * 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. + */ + +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; + +namespace Tizen.NUI.Physics2D.Chipmunk +{ + /// + /// Contact point sets make getting contact information simpler. There can be at most 2 contact + /// points. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public sealed class ContactPointSet : IEquatable + { +#pragma warning disable IDE0032 + private readonly int count; + private readonly Vect normal; + private readonly ContactPoint[] points; +#pragma warning restore IDE0032 + + private ContactPointSet(int count, Vect normal, ContactPoint[] points) + { + this.count = count; + this.normal = normal; + this.points = points; + } + + /// + /// Get the number of contact points in the contact set (maximum of two). + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public int Count => count; + + /// + /// Get the normal of the collision. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public Vect Normal => normal; + + /// + /// List of points in the contact point set + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public IReadOnlyList Points => points; + + /// + /// Return true if the contact point set is sequence-equal to another. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public bool Equals(ContactPointSet other) + { + if (ReferenceEquals(other, null) + || count != other.count + || normal != other.normal + || points.Length != other.points.Length) + { + return false; + } + + return points.SequenceEqual(other.points); + } + + /// + /// Get the hash code. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public override int GetHashCode() + { + var hashCode = -475635172; + + hashCode = hashCode * -1521134295 + count.GetHashCode(); + hashCode = hashCode * -1521134295 + normal.GetHashCode(); + hashCode = hashCode * -1521134295 + EqualityComparer.Default.GetHashCode(points); + + return hashCode; + } + + /// + /// Return true if the is sequence-equal to another. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public override bool Equals(object obj) + { + var other = obj as ContactPointSet; + + if (other == null) + { + return false; + } + + return Equals(other); + } + + /// + /// Return true if the contact point sets are sequence-equal. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public static bool operator ==(ContactPointSet left, ContactPointSet right) + { + if (ReferenceEquals(left, null)) + { + return ReferenceEquals(right, null); + } + + return left.Equals(right); + } + + /// + /// Return true if the contact point sets are sequence-inequal. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public static bool operator !=(ContactPointSet left, ContactPointSet right) + { + return !(left == right); + } + + internal static ContactPointSet FromContactPointSet(cpContactPointSet contactPointSet) + { + var points = new ContactPoint[2]; + + if (contactPointSet.count > 0) + { + points[0] = ContactPoint.FromCollidePoint(contactPointSet.points0); + } + else + { + points[0] = ContactPoint.Empty; + } + + if (contactPointSet.count > 1) + { + points[1] = ContactPoint.FromCollidePoint(contactPointSet.points1); + } + else + { + points[1] = ContactPoint.Empty; + } + + return new ContactPointSet( + contactPointSet.count, + contactPointSet.normal, + points); + } + + internal cpContactPointSet ToContactPointSet() + { + return new cpContactPointSet + { + normal = normal, + points0 = points[0].ToContactPoint(), + points1 = points[1].ToContactPoint(), + count = count + }; + } + } +} diff --git a/src/Tizen.NUI.Physics2D/src/public/chipmunk/DebugColor.cs b/src/Tizen.NUI.Physics2D/src/public/chipmunk/DebugColor.cs new file mode 100644 index 0000000..223e869 --- /dev/null +++ b/src/Tizen.NUI.Physics2D/src/public/chipmunk/DebugColor.cs @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2023 Codefoco (codefoco@codefoco.com) + * + * 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. + */ + +using System; +using System.ComponentModel; +using System.Runtime.InteropServices; + +namespace Tizen.NUI.Physics2D.Chipmunk +{ + /// + /// RGBA channels as floats used to represent the color for debug drawing. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + [StructLayout(LayoutKind.Sequential)] + public struct DebugColor : IEquatable + { +#pragma warning disable IDE0032 + private readonly float red; + private readonly float green; + private readonly float blue; + private readonly float alpha; +#pragma warning restore IDE0032 + + /// + /// Red component in the RGBA color space. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public float Red => red; + + /// + /// Green component in the RGBA color space. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public float Green => green; + + /// + /// Blue component in the RGBA color space. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public float Blue => blue; + + /// + /// Alpha component in the RGBA color space. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public float Alpha => alpha; + + /// + /// Create a with the given color channel values. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public DebugColor(float red, float green, float blue) + : this(red, green, blue, 1.0f) + { + } + + /// + /// Create a with the given color channel values. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public DebugColor(float red, float green, float blue, float alpha) + { + this.red = red; + this.green = green; + this.blue = blue; + this.alpha = alpha; + } + + /// + /// Check if a is equal to another object. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public override bool Equals(object obj) + { + var other = obj as DebugColor?; + + if (other == null) + return false; + + return Equals(other.Value); + } + + /// + /// Check if a is reference-equal to the other. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public bool Equals(DebugColor color) + { + return this == color; + } + + /// + /// Get the hash code. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public override int GetHashCode() + { + var hashCode = -1813971818; + + hashCode = hashCode * -1521134295 + red.GetHashCode(); + hashCode = hashCode * -1521134295 + green.GetHashCode(); + hashCode = hashCode * -1521134295 + blue.GetHashCode(); + hashCode = hashCode * -1521134295 + alpha.GetHashCode(); + + return hashCode; + } + + /// + /// Return a string formatted as "(R, G, B, A)". + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public override string ToString() + { + return $"({red},{green},{blue},{alpha})"; + } + + /// + /// Return true if two are reference-equal. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public static bool operator ==(DebugColor a, DebugColor b) + { +#pragma warning disable RECS0018 // Comparison of floating point numbers with equality operator + return a.red == b.red && + a.green == b.green && + a.blue == b.blue && + a.alpha == b.alpha; +#pragma warning restore RECS0018 // Comparison of floating point numbers with equality operator + } + + + /// + /// Return true if two are not reference-equal. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public static bool operator !=(DebugColor a, DebugColor b) + { + return !(a == b); + } + } +} diff --git a/src/Tizen.NUI.Physics2D/src/public/chipmunk/DebugDrawColors.cs b/src/Tizen.NUI.Physics2D/src/public/chipmunk/DebugDrawColors.cs new file mode 100644 index 0000000..a64e7ea --- /dev/null +++ b/src/Tizen.NUI.Physics2D/src/public/chipmunk/DebugDrawColors.cs @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2023 Codefoco (codefoco@codefoco.com) + * + * 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. + */ + +using System.ComponentModel; + +namespace Tizen.NUI.Physics2D.Chipmunk +{ + /// + /// Default DebugColors for ShapeOutline, Constraint and CollisionPoint + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public class DebugDrawColors + { +#pragma warning disable IDE0032 + static readonly DebugDrawColors defaultColors = new DebugDrawColors() + { + ShapeOutline = new DebugColor(1, 1, 1), + Constraint = new DebugColor(0, 1, 0), + CollisionPoint = new DebugColor(1, 0, 1) + }; +#pragma warning restore IDE0032 + + /// + /// Shape outline color. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public DebugColor ShapeOutline { get; set; } + + /// + /// Constraint color. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public DebugColor Constraint { get; set; } + + /// + /// Collision point color. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public DebugColor CollisionPoint { get; set; } + + /// + /// The Default DebugDrawColors. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public static DebugDrawColors Default => defaultColors; + + } +} diff --git a/src/Tizen.NUI.Physics2D/src/public/chipmunk/DebugDrawFlags.cs b/src/Tizen.NUI.Physics2D/src/public/chipmunk/DebugDrawFlags.cs new file mode 100644 index 0000000..31e13c9 --- /dev/null +++ b/src/Tizen.NUI.Physics2D/src/public/chipmunk/DebugDrawFlags.cs @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2023 Codefoco (codefoco@codefoco.com) + * + * 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. + */ + +using System; +using System.ComponentModel; + +namespace Tizen.NUI.Physics2D.Chipmunk +{ + /// + /// Flags to enable or disable DebugDrawing. + /// + [Flags] + [EditorBrowsable(EditorBrowsableState.Never)] + public enum DebugDrawFlags + { + /// + /// Draw nothing. + /// + None = 0, + + /// + /// Draw Shapes. + /// + Shapes = 1 << 0, + + /// + /// Draw Constraints. + /// + Constraints = 1 << 1, + + /// + /// Draw Collision Points. + /// + CollisionPoints = 1 << 2, + + /// + /// Draw All. + /// + All = Shapes | Constraints | CollisionPoints + } +} diff --git a/src/Tizen.NUI.Physics2D/src/public/chipmunk/HastySpace.cs b/src/Tizen.NUI.Physics2D/src/public/chipmunk/HastySpace.cs new file mode 100644 index 0000000..5c0e1ce --- /dev/null +++ b/src/Tizen.NUI.Physics2D/src/public/chipmunk/HastySpace.cs @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2023 Codefoco (codefoco@codefoco.com) + * + * 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. + */ + +using System; +using System.ComponentModel; + +namespace Tizen.NUI.Physics2D.Chipmunk +{ + /// + /// Similar to , but with ARM NEON optimizations in the solver. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public sealed class HastySpace : Space + { + /// + /// On ARM platforms that support NEON, this will enable the vectorized solver. + /// also supports multiple threads, but runs single threaded by + /// default for determinism. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public HastySpace() + : base(NativeMethods.cpHastySpaceNew()) + { + } + + /// + /// The number of threads to use for the solver. Currently Chipmunk is limited to 2 threads + /// as using more generally provides very minimal performance gains. Passing 0 as the thread + /// count on iOS or OS X will cause Chipmunk to automatically detect the number of threads + /// it should use. On other platforms passing 0 for the thread count will set 1 thread. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public int Threads + { + get => (int)NativeMethods.cpHastySpaceGetThreads(Handle); + set => NativeMethods.cpHastySpaceSetThreads(Handle, (uint)value); + } + + /// + /// Step in the hasty space. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public sealed override void Step(double dt) + { + NativeMethods.cpHastySpaceStep(Handle, dt); + } + + /// + /// Destroy and free the hasty space. + /// + protected override void FreeSpace(IntPtr handle) + { + NativeMethods.cpHastySpaceFree(handle); + } + } +} diff --git a/src/Tizen.NUI.Physics2D/src/public/chipmunk/IDebugDraw.cs b/src/Tizen.NUI.Physics2D/src/public/chipmunk/IDebugDraw.cs new file mode 100644 index 0000000..2ea82a5 --- /dev/null +++ b/src/Tizen.NUI.Physics2D/src/public/chipmunk/IDebugDraw.cs @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2023 Codefoco (codefoco@codefoco.com) + * + * 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. + */ + +using System.ComponentModel; + +namespace Tizen.NUI.Physics2D.Chipmunk +{ + /// + /// Interface to draw debug primitives (circle, point, segment). + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public interface IDebugDraw + { + /// + /// Draw stroked circle. + /// + void DrawCircle(Vect pos, double angle, double radius, DebugColor outlineColor, DebugColor fillColor); + + /// + /// Draws a line segment. + /// + void DrawSegment(Vect a, Vect b, DebugColor color); + + /// + /// Draws a thick line segment. + /// + void DrawFatSegment(Vect a, Vect b, double radius, DebugColor outlineColor, DebugColor fillColor); + + /// + /// Draws a convex polygon. + /// + void DrawPolygon(Vect[] vectors, double radius, DebugColor outlineColor, DebugColor fillColor); + + /// + /// Draws a dot. + /// + void DrawDot(double size, Vect pos, DebugColor color); + + /// + /// Returns a color for a given shape. This gives you an opportunity to color shapes based + /// on how they are used in your engine. + /// + DebugColor ColorForShape(Shape shape); + } +} diff --git a/src/Tizen.NUI.Physics2D/src/public/chipmunk/MarchData.cs b/src/Tizen.NUI.Physics2D/src/public/chipmunk/MarchData.cs new file mode 100644 index 0000000..c5e5d76 --- /dev/null +++ b/src/Tizen.NUI.Physics2D/src/public/chipmunk/MarchData.cs @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2023 Codefoco (codefoco@codefoco.com) + * + * 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. + */ + +using System; +using System.ComponentModel; + +namespace Tizen.NUI.Physics2D.Chipmunk +{ + /// + /// March data used for . + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public class MarchData + { + /// + /// The bounding box. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public BoundingBox BoundingBox { get; set; } + + /// + /// The number of horizontal samples. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public int XSamples { get; set; } + + /// + /// The number of vertical samples. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public int YSamples { get; set; } + + /// + /// The threshold. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public double Threshold { get; set; } + + /// + /// Callback for sampling/ + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public Func SampleFunction { get; set; } + + /// + /// Callback for segmentation. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public Action SegmentFunction { get; set; } + + /// + /// User sample data. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public object SampleData { get; set; } + + /// + /// User segmentation data. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public object SegmentData { get; set; } + } +} diff --git a/src/Tizen.NUI.Physics2D/src/public/chipmunk/PointQueryInfo.cs b/src/Tizen.NUI.Physics2D/src/public/chipmunk/PointQueryInfo.cs new file mode 100644 index 0000000..aead09b --- /dev/null +++ b/src/Tizen.NUI.Physics2D/src/public/chipmunk/PointQueryInfo.cs @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2023 Codefoco (codefoco@codefoco.com) + * + * 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. + */ + +using System; +using System.ComponentModel; + +namespace Tizen.NUI.Physics2D.Chipmunk +{ + /// + /// holds the result of a point query made on a + /// or . + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public sealed class PointQueryInfo : IEquatable + { +#pragma warning disable IDE0032 + private readonly Shape shape; + private readonly Vect point; + private readonly double distance; + private readonly Vect gradient; +#pragma warning restore IDE0032 + + /// + /// The nearest shape, None if no shape was within range. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public Shape Shape => shape; + + /// + /// The closest point on the shape’s surface (in world space coordinates). + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public Vect Point => point; + + /// + /// The distance to the point. The distance is negative if the point is inside the shape. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public double Distance => distance; + + /// + /// The gradient of the signed distance function. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public Vect Gradient => gradient; + + /// + /// Create a . + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public PointQueryInfo(Shape s, Vect p, double d, Vect g) + { + shape = s; + point = p; + distance = d; + gradient = g; + } + + /// + /// Return true if this object is reference-equal to the given + /// object. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public override bool Equals(object obj) + { + var other = obj as PointQueryInfo; + + if (other == null) + { + return false; + } + + return this == other; + } + + /// + /// Get the hash code. + /// + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public override int GetHashCode() + { + return shape.Handle.ToInt32() ^ + point.GetHashCode() ^ + distance.GetHashCode() ^ + (gradient.GetHashCode() << 4); + } + + /// + /// Return true if this object is reference-equal to the given + /// object. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public static bool operator ==(PointQueryInfo left, PointQueryInfo right) + { + if (ReferenceEquals(left, null)) + { + return ReferenceEquals(right, null); + } + + return left.Equals(right); + } + + /// + /// Return true if this object is not reference-equal to the + /// given object. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public static bool operator !=(PointQueryInfo a, PointQueryInfo b) + { + return !(a == b); + } + + internal static PointQueryInfo FromQueryInfo(cpPointQueryInfo queryInfo) + { + var shape = Shape.FromHandle(queryInfo.shape); + + return new PointQueryInfo( + shape, + queryInfo.point, + queryInfo.distance, + queryInfo.gradient); + } + + /// + /// Return true if this object's distance is within + /// of the other and all other fields are equivalent. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public bool Equals(PointQueryInfo other) + { + if (ReferenceEquals(other, null) || + shape.Handle != other.shape.Handle || + point != other.point || + gradient != other.gradient) + { + return false; + } + + return Math.Abs(distance - other.distance) < float.Epsilon; + } + } +} diff --git a/src/Tizen.NUI.Physics2D/src/public/chipmunk/SegmentQueryInfo.cs b/src/Tizen.NUI.Physics2D/src/public/chipmunk/SegmentQueryInfo.cs new file mode 100644 index 0000000..2a97790 --- /dev/null +++ b/src/Tizen.NUI.Physics2D/src/public/chipmunk/SegmentQueryInfo.cs @@ -0,0 +1,178 @@ +/* + * Copyright (c) 2023 Codefoco (codefoco@codefoco.com) + * + * 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. + */ + +using System; +using System.ComponentModel; + +namespace Tizen.NUI.Physics2D.Chipmunk +{ + /// + /// Segment queries return where a shape was hit and its surface normal at the point of contact. + /// Use == null to test if a shape was hit. Segment queries + /// are like ray casting, but because not all spatial indexes allow processing infinitely long + /// ray queries, it's limited to segments. In practice, this is still very fast and you don’t + /// need to worry too much about the performance as long as you aren’t using extremely long + /// segments for your queries. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public sealed class SegmentQueryInfo : IEquatable + { +#pragma warning disable IDE0032 + private readonly Shape shape; + private readonly Vect point; + private readonly Vect normal; + private readonly double alpha; +#pragma warning restore IDE0032 + + /// + /// Shape that was hit, or None if no collision occured. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public Shape Shape => shape; + + /// + /// The point of impact. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public Vect Point => point; + + /// + /// The normal of the surface that was hit. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public Vect Normal => normal; + + /// + /// The normalized distance along the query segment in the range [0, 1] + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public double Alpha => alpha; + + /// + /// Construct a Segment query info. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public SegmentQueryInfo(Shape s, Vect p, Vect n, double a) + { + shape = s; + point = p; + normal = n; + alpha = a; + } + + /// + /// Return true if the given object is reference-equal to this one. + /// + /// + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public override bool Equals(object obj) + { + var other = obj as SegmentQueryInfo; + + if (other == null) + { + return false; + } + + return this == other; + } + + /// + /// Return true if both objects are reference-equal to each other. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public static bool operator ==(SegmentQueryInfo left, SegmentQueryInfo right) + { + if (ReferenceEquals(left, null)) + { + return ReferenceEquals(right, null); + } + + return left.Equals(right); + } + + /// + /// Return true if both objects are not reference-equal to each other. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public static bool operator !=(SegmentQueryInfo a, SegmentQueryInfo b) + { + return !(a == b); + } + + /// + /// Create a SegmentQuery from a native struct cpSegmentQueryInfo. + /// + internal static SegmentQueryInfo FromQueryInfo(cpSegmentQueryInfo queryInfo) + { + Shape shape; + + if (queryInfo.shape == IntPtr.Zero) + { + shape = null; + } + else + { + shape = Shape.FromHandle(queryInfo.shape); + } + + return new SegmentQueryInfo( + shape, + queryInfo.point, + queryInfo.normal, + queryInfo.alpha); + } + + /// + /// Return true if the fields in both objects are equivalent and the + /// field is within of the other's. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public bool Equals(SegmentQueryInfo other) + { + if (ReferenceEquals(other, null) || + shape?.Handle != other.shape?.Handle || + point != other.point || + normal != other.normal) + { + return false; + } + + return Math.Abs(alpha - other.alpha) < float.Epsilon; + } + + /// + /// Get the hash code. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public override int GetHashCode() + { + var hashCode = -1275187100; + hashCode = hashCode * -1521134295 + shape.GetHashCode(); + hashCode = hashCode * -1521134295 + point.GetHashCode(); + hashCode = hashCode * -1521134295 + normal.GetHashCode(); + hashCode = hashCode * -1521134295 + alpha.GetHashCode(); + return hashCode; + } + } +} diff --git a/src/Tizen.NUI.Physics2D/src/public/chipmunk/ShapeFilter.cs b/src/Tizen.NUI.Physics2D/src/public/chipmunk/ShapeFilter.cs new file mode 100755 index 0000000..45cb76b --- /dev/null +++ b/src/Tizen.NUI.Physics2D/src/public/chipmunk/ShapeFilter.cs @@ -0,0 +1,117 @@ +/* + * Copyright(c) 2023 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +using System; +using System.ComponentModel; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace Tizen.NUI.Physics2D.Chipmunk +{ + /// + /// Fast collision filtering type that is used to determine if two objects collide before calling collision or query callbacks. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + [StructLayout(LayoutKind.Sequential)] + public struct ShapeFilter + { + private static readonly UIntPtr no_group = (UIntPtr)0; + private static readonly uint all_categories = (~(uint)0); + + private static readonly ShapeFilter filter_all = new ShapeFilter(no_group, all_categories, all_categories); + private static readonly ShapeFilter filter_none = new ShapeFilter(no_group, ~all_categories, ~all_categories); + + private UIntPtr group; + private uint categories; + private uint mask; + + /// + /// Group value + /// Two objects with the same non-zero group value do not collide. + /// This is generally used to group objects in a composite object together to disable self collisions. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public UIntPtr Group + { + get => group; + set => group = value; + } + + /// + /// Categories value + /// A bitmask of user definable categories that this object belongs to. + /// The category/mask combinations of both objects in a collision must agree for a collision to occur. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public uint Categories + { + get => categories; + set => categories = value; + } + + /// + /// Mask value + /// A bitmask of user definable category types that this object object collides with. + /// The category/mask combinations of both objects in a collision must agree for a collision to occur. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public uint Mask + { + get => mask; + set => mask = value; + } + + /// + /// Create a shape filter. + /// + /// + /// + /// + [EditorBrowsable(EditorBrowsableState.Never)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public ShapeFilter(UIntPtr group, uint categories, uint mask) + { + this.group = group; + this.categories = categories; + this.mask = mask; + } + + /// + /// Value for signifying that a shape is in no group. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public static UIntPtr NO_GROUP => no_group; + + /// + /// Value for signifying that a shape is in every layer. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public static uint ALL_CATEGORIES => all_categories; + + /// + /// Collision filter value for a shape that will collide with anything except FILTER_NONE. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public static ShapeFilter FILTER_ALL => filter_all; + + /// + /// Collision filter value for a shape that does not collide with anything. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public static ShapeFilter FILTER_NONE => filter_none; + } +} diff --git a/src/Tizen.NUI.Physics2D/src/public/chipmunk/Shapes/Box.cs b/src/Tizen.NUI.Physics2D/src/public/chipmunk/Shapes/Box.cs new file mode 100644 index 0000000..1ffd9a1 --- /dev/null +++ b/src/Tizen.NUI.Physics2D/src/public/chipmunk/Shapes/Box.cs @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2023 Codefoco (codefoco@codefoco.com) + * + * 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. + */ + +using System.ComponentModel; + +namespace Tizen.NUI.Physics2D.Chipmunk +{ + /// + /// A retangular shape shape + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public class Box : Shape + { + /// + /// Create and initialize a box polygon shape. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public Box(Body body, double width, double height, double radius) + : base(NativeMethods.cpBoxShapeNew(body.Handle, width, height, radius)) + { + + } + + /// + /// Create and initialize an offset box polygon shape. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public Box(Body body, BoundingBox box, double radius) + : base(NativeMethods.cpBoxShapeNew2(body.Handle, box, radius)) + { + + } + + /// + /// Calculate the moment of inertia for a solid box. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public static double MomentForBox(double mass, double width, double height) + { + return NativeMethods.cpMomentForBox(mass, width, height); + } + + /// + /// Calculate the moment of inertia for a solid box. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public static double MomentForBox(double mass, BoundingBox boundingBox) + { + return NativeMethods.cpMomentForBox2(mass, boundingBox); + } + } +} diff --git a/src/Tizen.NUI.Physics2D/src/public/chipmunk/Shapes/Circle.cs b/src/Tizen.NUI.Physics2D/src/public/chipmunk/Shapes/Circle.cs new file mode 100644 index 0000000..252cf67 --- /dev/null +++ b/src/Tizen.NUI.Physics2D/src/public/chipmunk/Shapes/Circle.cs @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2023 Codefoco (codefoco@codefoco.com) + * + * 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. + */ + +using System.ComponentModel; + +namespace Tizen.NUI.Physics2D.Chipmunk +{ + /// + /// A circle shape defined by a radius + /// This is the fastest and simplest collision shape + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public class Circle : Shape + { + /// + /// Create and initialize a circle polygon shape. + /// + /// The body to attach the circle to. + /// The radius of the circle. + [EditorBrowsable(EditorBrowsableState.Never)] + public Circle(Body body, double radius) + : this(body, radius, Vect.Zero) + { + } + + /// + /// Create and initialize an offset circle polygon shape. + /// + /// The body to attach the circle to. + /// The radius of the circle. + /// + /// The offset from the body's center of gravity in coordinates local to the body. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public Circle(Body body, double radius, Vect offset) + : base(NativeMethods.cpCircleShapeNew(body.Handle, radius, offset)) + { + } + + /// + /// Get the offset of the circle. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public Vect Offset => NativeMethods.cpCircleShapeGetOffset(Handle); + + /// + /// Get the radius of the circle. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public double Radius => NativeMethods.cpCircleShapeGetRadius(Handle); + + /// + /// Get the calculated area of the circle. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public new double Area => AreaForCircle(0.0, Radius); + + /// + /// Calculate the moment of the circle for the given mass. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public double MomentForMass(double mass) + { + return MomentForCircle(mass, Radius, Offset); + } + + /// + /// Calculate the moment of inertia for the circle. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public static double MomentForCircle(double mass, double innerRadius, double radius, Vect offset) + { + return NativeMethods.cpMomentForCircle(mass, innerRadius, radius, offset); + } + + /// + /// Calculate the moment of inertia for the circle. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public static double MomentForCircle(double mass, double radius, Vect offset) + { + return NativeMethods.cpMomentForCircle(mass, 0.0, radius, offset); + } + + /// + /// Calculate the area of a circle or donut. + /// + /// + /// The radius of the 'donut hole', which defines the area missing. + /// + /// + /// The outer radius of the donut. This should be greater than the + /// . + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public static double AreaForCircle(double innerRadius, double radius) + { + return NativeMethods.cpAreaForCircle(innerRadius, radius); + } + } +} diff --git a/src/Tizen.NUI.Physics2D/src/public/chipmunk/Shapes/Polygon.cs b/src/Tizen.NUI.Physics2D/src/public/chipmunk/Shapes/Polygon.cs new file mode 100644 index 0000000..986f70f --- /dev/null +++ b/src/Tizen.NUI.Physics2D/src/public/chipmunk/Shapes/Polygon.cs @@ -0,0 +1,194 @@ +/* + * Copyright (c) 2023 Codefoco (codefoco@codefoco.com) + * + * 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. + */ + +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Diagnostics; + +namespace Tizen.NUI.Physics2D.Chipmunk +{ + /// + /// A polygon shape composed of connected vertices. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public class Polygon : Shape + { + /// + /// A convex polygon shape. It's the slowest, but most flexible collision shape. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public Polygon(Body body, IReadOnlyList verts, Transform transform, double radius) + : base(CreatePolygonShape(body, verts, transform, radius)) + { + } + + /// + /// Allocate and initialize a polygon shape with rounded corners. + /// The vertexes must be convex with a counter-clockwise winding. + /// + /// + /// + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public Polygon(Body body, Vect[] verts, double radius) + : base(CreatePolygonShape(body, verts, radius)) + { + + } + + private static IntPtr CreatePolygonShape(Body body, IReadOnlyList verts, Transform transform, double radius) + { + Debug.Assert(verts.Count > 2); + + IntPtr ptrVectors = NativeInterop.StructureArrayToPtr(verts); + + IntPtr handle = NativeMethods.cpPolyShapeNew(body.Handle, verts.Count, ptrVectors, transform, radius); + + NativeInterop.FreeStructure(ptrVectors); + + return handle; + } + + private static IntPtr CreatePolygonShape(Body body, Vect[] verts, double radius) + { + Debug.Assert(verts.Length > 2); + + IntPtr ptrVectors = NativeInterop.StructureArrayToPtr(verts); + + IntPtr handle = NativeMethods.cpPolyShapeNewRaw(body.Handle, verts.Length, ptrVectors, radius); + + NativeInterop.FreeStructure(ptrVectors); + + return handle; + } + + /// + /// Get the number of vertices in a polygon shape. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public int Count => NativeMethods.cpPolyShapeGetCount(Handle); + + /// + /// Get the th vertex of a polygon shape. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public Vect GetVertex(int i) + { + return NativeMethods.cpPolyShapeGetVert(Handle, i); + } + + /// + /// Get the vertices of the polygon. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public IReadOnlyList Vertices + { + get + { + int count = Count; + if (count == 0) + return Array.Empty(); + + Vect[] vertices = new Vect[count]; + + for (int i = 0; i < count; i++) + { + vertices[i] = GetVertex(i); + } + + return vertices; + } + } + + /// + /// Get the radius of the polygon. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public double Radius => NativeMethods.cpPolyShapeGetRadius(Handle); + + /// + /// Get and calculate the signed area of this polygon. Vertices specified such that they connect in + /// a clockwise fashion (called winding) give a positive area measurement. This is probably + /// backwards to what you might expect. + /// + + /// + /// Get and calculate the signed area of the polygon. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public new double Area => AreaForPoly(Vertices, Radius); + + /// + /// Get and calculate the centroid of the polygon. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public Vect Centroid => CentroidForPoly(Vertices); + + /// + /// Calculate the moment of inertia for a solid polygon shape assuming its center of gravity + /// is at its centroid. The offset is added to each vertex. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public static double MomentForPolygon(double mass, IReadOnlyList vertices, Vect offset, double radius) + { + IntPtr verticesPtr = NativeInterop.StructureArrayToPtr(vertices); + double moment = NativeMethods.cpMomentForPoly(mass, vertices.Count, verticesPtr, offset, radius); + + NativeInterop.FreeStructure(verticesPtr); + + return moment; + } + + /// + /// Calculate the signed area of this polygon. Vertices specified such that they connect in + /// a clockwise fashion (called winding) give a positive area measurement. This is probably + /// backwards to what you might expect. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public static double AreaForPoly(IReadOnlyList vertices, double radius) + { + IntPtr verticesPtr = NativeInterop.StructureArrayToPtr(vertices); + + double area = NativeMethods.cpAreaForPoly(vertices.Count, verticesPtr, radius); + + NativeInterop.FreeStructure(verticesPtr); + + return area; + } + + /// + /// Calculate the natural centroid of a polygon. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public static Vect CentroidForPoly(IReadOnlyList vertices) + { + IntPtr verticesPtr = NativeInterop.StructureArrayToPtr(vertices); + + Vect centroid = NativeMethods.cpCentroidForPoly(vertices.Count, verticesPtr); + + NativeInterop.FreeStructure(verticesPtr); + + return centroid; + } + } +} diff --git a/src/Tizen.NUI.Physics2D/src/public/chipmunk/Shapes/Segment.cs b/src/Tizen.NUI.Physics2D/src/public/chipmunk/Shapes/Segment.cs new file mode 100644 index 0000000..66e8a4b --- /dev/null +++ b/src/Tizen.NUI.Physics2D/src/public/chipmunk/Shapes/Segment.cs @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2023 Codefoco (codefoco@codefoco.com) + * + * 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. + */ + +using System.ComponentModel; + +namespace Tizen.NUI.Physics2D.Chipmunk +{ + /// + /// A line segment shape between two points, which is mainly useful when it behaves statically, + /// though it can be beveled to give it thickness. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public class Segment : Shape + { + /// + /// Create a line segment. + /// + /// The body to attach the segment to. + /// The first endpoint of the segment. + /// The second endpoint of the segment. + /// The thickness of the segment. + [EditorBrowsable(EditorBrowsableState.Never)] + public Segment(Body body, Vect a, Vect b, double radius) + : base(NativeMethods.cpSegmentShapeNew(body.Handle, a, b, radius)) + { + } + + /// + /// Let Chipmunk know about the geometry of adjacent segments to avoid colliding with endcaps. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public void SetNeighbors(Vect prev, Vect next) + { + NativeMethods.cpSegmentShapeSetNeighbors(Handle, prev, next); + } + + /// + /// Get the first endpoint of the segment shape. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public Vect A => NativeMethods.cpSegmentShapeGetA(Handle); + + /// + /// Get the second endpoint of the segment shape. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public Vect B => NativeMethods.cpSegmentShapeGetB(Handle); + + /// + /// Get the normal of the segment shape. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public Vect Normal => NativeMethods.cpSegmentShapeGetNormal(Handle); + + /// + /// Get the segment radius. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public double Radius => NativeMethods.cpSegmentShapeGetRadius(Handle); + + /// + /// Calculate the area of the segment, assuming a thickness has been provided. The area is + /// calculated assuming the endpoints would be rounded, like a capsule. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public new double Area => AreaForSegment(A, B, Radius); + + /// + /// Calculate the moment of inertia of the segment. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public double MomentForMass(double mass) + { + return MomentForSegment(mass, A, B, Radius); + } + + /// + /// Calculate the moment of inertia for the line segment. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public static double MomentForSegment(double mass, Vect a, Vect b, double radius) + { + return NativeMethods.cpMomentForSegment(mass, a, b, radius); + } + + /// + /// Calculate the area of a segment, assuming a thickness has been provided. The area is + /// calculated assuming the endpoints would be rounded, like a capsule. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public static double AreaForSegment(Vect a, Vect b, double radius) + { + return NativeMethods.cpAreaForSegment(a, b, radius); + } + } +} diff --git a/src/Tizen.NUI.Physics2D/src/public/chipmunk/Shapes/Shape.cs b/src/Tizen.NUI.Physics2D/src/public/chipmunk/Shapes/Shape.cs new file mode 100644 index 0000000..19259a0 --- /dev/null +++ b/src/Tizen.NUI.Physics2D/src/public/chipmunk/Shapes/Shape.cs @@ -0,0 +1,327 @@ +/* + * Copyright (c) 2023 Codefoco (codefoco@codefoco.com) + * + * 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. + */ + +using System; +using System.ComponentModel; +using System.Diagnostics; +using System.Runtime.InteropServices; +using cpBody = System.IntPtr; +using cpDataPointer = System.IntPtr; +using cpShape = System.IntPtr; +using cpSpace = System.IntPtr; + +namespace Tizen.NUI.Physics2D.Chipmunk +{ + /// + /// Abstract Chipmunk Shape + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public abstract class Shape : IDisposable + { +#pragma warning disable IDE0032 + private readonly cpShape shape; +#pragma warning restore IDE0032 + + /// + /// Create a Shape with the given . + /// + /// The native shape handle. + internal protected Shape(cpShape shapeHandle) + { + shape = shapeHandle; + RegisterUserData(); + } + + /// + /// The native handle. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public cpShape Handle => shape; + + /// + /// Register managed object in the native user data. + /// + private void RegisterUserData() + { + cpDataPointer pointer = NativeInterop.RegisterHandle(this); + NativeMethods.cpShapeSetUserData(shape, pointer); + } + + void ReleaseUserData() + { + cpDataPointer pointer = NativeMethods.cpShapeGetUserData(shape); + NativeInterop.ReleaseHandle(pointer); + } + + /// + /// Get a managed Shape from a native handle. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public static Shape FromHandle(cpShape shape) + { + cpDataPointer handle = NativeMethods.cpShapeGetUserData(shape); + + return NativeInterop.FromIntPtr(handle); + } + + /// + /// Dispose the shape. + /// + protected virtual void Dispose(bool dispose) + { + if (!dispose) + { + Debug.WriteLine("Disposing shape {0} on finalizer... (consider Dispose explicitly)", shape); + } + + Free(); + } + + /// + /// Destroy and free the shape. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public void Free() + { + ReleaseUserData(); + NativeMethods.cpShapeFree(shape); + } + + /// + /// Destroy and free the shape. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + // Shape properties + + /// + /// Arbitrary user data. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public object Data { get; set; } + + /// + /// Gets the space that this shape is registered within. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public Space Space + { + get + { + cpSpace space = NativeMethods.cpShapeGetSpace(shape); + return Space.FromHandleSafe(space); + } + } + + /// + /// The body that this shape is associated with. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public Body Body + { + get + { + cpBody body = NativeMethods.cpShapeGetBody(shape); + return Body.FromHandleSafe(body); + } + set + { + Debug.Assert(value != null && Space == null, + "Body can't be null and you can only change body if the shape wasn't added to space"); + + NativeMethods.cpShapeSetBody(shape, value.Handle); + } + } + + /// + /// Mass of the shape to have Chipmunk calculate mass properties for you. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public double Mass + { + get => NativeMethods.cpShapeGetMass(shape); + set => NativeMethods.cpShapeSetMass(shape, value); + } + + /// + /// Density of the shape if you are having Chipmunk calculate mass properties for you. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public double Density + { + get => NativeMethods.cpShapeGetDensity(shape); + set => NativeMethods.cpShapeSetDensity(shape, value); + } + + /// + /// Get the calculated moment of inertia for the shape. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public double Moment => NativeMethods.cpShapeGetMoment(shape); + + /// + /// Get the calculated area of the shape. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public double Area => NativeMethods.cpShapeGetArea(shape); + + /// + /// Get the center of gravity of the shape. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public Vect CenterOfGravity => NativeMethods.cpShapeGetCenterOfGravity(shape); + + /// + /// Get the bounding box that contains the shape, given it's current position and angle. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public BoundingBox BoundingBox => NativeMethods.cpShapeGetBB(shape); + + /// + /// Whether the shape is a sensor. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public bool Sensor + { + get => NativeMethods.cpShapeGetSensor(shape) != 0; + set => NativeMethods.cpShapeSetSensor(shape, value ? (byte)1 : (byte)0); + } + + /// + /// The elasticity of the shape. A value of 0.0 is perfectly inelastic (no bounce). A + /// value of 1.0 is perfectly elastic. Due to simulation inaccuracy, values of 1.0 or + /// greater are not recommended. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public double Elasticity + { + get => NativeMethods.cpShapeGetElasticity(shape); + set => NativeMethods.cpShapeSetElasticity(shape, value); + } + + /// + /// The friction coefficient, following the Coulomb friction model. A value of 0.0 is + /// frictionless. https://en.wikipedia.org/wiki/Friction#Coefficient_of_friction + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public double Friction + { + get => NativeMethods.cpShapeGetFriction(shape); + set => NativeMethods.cpShapeSetFriction(shape, value); + } + + /// + /// The surface velocity of the object. Useful for creating conveyor belts or players that + /// move around. This value is only used when calculating friction, not resolving the + /// collision. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public Vect SurfaceVelocity + { + get => NativeMethods.cpShapeGetSurfaceVelocity(shape); + set => NativeMethods.cpShapeSetSurfaceVelocity(shape, value); + } + + /// + /// An arbitrary value representing the collision type of this shape. Only shapes with like + /// collision types will collide. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public int CollisionType + { + get => (int)(uint)NativeMethods.cpShapeGetCollisionType(shape); + set => NativeMethods.cpShapeSetCollisionType(shape, (UIntPtr)(uint)value); + } + + /// + /// An arbitrary value representing the collision type of this shape. Only shapes with like + /// collision types will collide. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public ShapeFilter Filter + { + get => (ShapeFilter)NativeMethods.cpShapeGetFilter(shape); + set => NativeMethods.cpShapeSetFilter(shape, (ShapeFilter)value); + } + + /// + /// Update, cache and return the bounding box of a shape based on the body it's attached to. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public BoundingBox CacheBB() + { + return NativeMethods.cpShapeCacheBB(shape); + } + + /// + /// Update, cache and return the bounding box of a shape with an explicit transformation. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public BoundingBox Update(Transform transform) + { + return NativeMethods.cpShapeUpdate(shape, transform); + } + + /// + /// Finds the point on the surface of the shape which is closest to the given point. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public PointQueryInfo PointQuery(Vect point) + { + var output = new cpPointQueryInfo(); + NativeMethods.cpShapePointQuery(shape, point, ref output); + + return PointQueryInfo.FromQueryInfo(output); + } + + /// + /// Perform a segment query against a shape. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public SegmentQueryInfo SegmentQuery(Vect a, Vect b, double radius) + { + var queryInfo = new cpSegmentQueryInfo(); + NativeMethods.cpShapeSegmentQuery(shape, a, b, radius, ref queryInfo); + + return SegmentQueryInfo.FromQueryInfo(queryInfo); + } + + /// + /// Get the contact information between two shapes. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public ContactPointSet Collide(Shape other) + { + Debug.Assert(Marshal.SizeOf(typeof(cpContactPointSet)) == 104, + "check Chipmunk sizeof(cpContactPointSet)"); + + cpContactPointSet contactPointSet = NativeMethods.cpShapesCollide(shape, other.Handle); + + return ContactPointSet.FromContactPointSet(contactPointSet); + } + } +} diff --git a/src/Tizen.NUI.Physics2D/src/public/chipmunk/Space.cs b/src/Tizen.NUI.Physics2D/src/public/chipmunk/Space.cs new file mode 100755 index 0000000..df8c661 --- /dev/null +++ b/src/Tizen.NUI.Physics2D/src/public/chipmunk/Space.cs @@ -0,0 +1,851 @@ +/* + * Copyright (c) 2023 Codefoco (codefoco@codefoco.com) + * + * 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. + */ + +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Diagnostics; +using System.Runtime.InteropServices; +using cpBody = System.IntPtr; +using cpCollisionHandlerPointer = System.IntPtr; +using cpCollisionType = System.UIntPtr; +using cpConstraint = System.IntPtr; +using cpDataPointer = System.IntPtr; +using cpShape = System.IntPtr; +using cpSpace = System.IntPtr; +using voidptr_t = System.IntPtr; + +#if __IOS__ || __TVOS__ || __WATCHOS__ || __MACCATALYST__ +using ObjCRuntime; +#endif + +namespace Tizen.NUI.Physics2D.Chipmunk +{ + /// + /// Spaces in Chipmunk are the basic unit of simulation. You add rigid bodies, shapes, and + /// constraints to the space and then step them all forward through time together. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public class Space : IDisposable + { +#pragma warning disable IDE0032 + private readonly cpSpace space; +#pragma warning restore IDE0032 + + /// + /// Native handle cpSpace. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public cpSpace Handle => space; + + /// + /// Create a new Space object. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public Space() + { + space = NativeMethods.cpSpaceNew(); + RegisterUserData(); + } + + /// + /// Create a space from a native Handle (used by derived classes). + /// + /// + protected internal Space(cpSpace handle) + { + space = handle; + RegisterUserData(); + } + + /// + /// Destroys and frees. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public void Free() + { + ReleaseUserData(); + FreeSpace(space); + } + + /// + /// Destroy and free space. + /// + /// + protected virtual void FreeSpace(cpSpace handle) + { + NativeMethods.cpSpaceFree(handle); + } + + /// + /// Destroy and free space. + /// + protected virtual void Dispose(bool disposing) + { + Free(); + } + /// + /// Disposes the Space object. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + void RegisterUserData() + { + cpDataPointer pointer = NativeInterop.RegisterHandle(this); + NativeMethods.cpSpaceSetUserData(space, pointer); + } + + void ReleaseUserData() + { + cpDataPointer pointer = NativeMethods.cpSpaceGetUserData(space); + NativeInterop.ReleaseHandle(pointer); + } + + /// + /// Get a Space object from native cpSpace handle. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public static Space FromHandle(cpSpace space) + { + cpDataPointer handle = NativeMethods.cpSpaceGetUserData(space); + return NativeInterop.FromIntPtr(handle); + } + + /// + /// Get a Space object from native cpSpace handle, but return null if the handle is 0. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public static Space FromHandleSafe(cpSpace space) + { + if (space == IntPtr.Zero) + { + return null; + } + + return FromHandle(space); + } + + // Properties + + /// + /// Arbitrary user data. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public object Data { get; set; } + + /// + /// Number of iterations to use in the impulse solver to solve contacts and other + /// constraints. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public int Iterations + { + get => NativeMethods.cpSpaceGetIterations(space); + set => NativeMethods.cpSpaceSetIterations(space, value); + } + + /// + /// Gravity to pass to rigid bodies when integrating velocity. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public Vect Gravity + { + get => NativeMethods.cpSpaceGetGravity(space); + set => NativeMethods.cpSpaceSetGravity(space, value); + } + + /// + /// Damping rate expressed as the fraction of velocity that bodies retain each second. A + /// value of 0.9 would mean that each body's velocity will drop 10% per second. The default + /// value is 1.0, meaning no damping is applied. Note: This damping value is different than + /// those of and . + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public double Damping + { + get => NativeMethods.cpSpaceGetDamping(space); + set => NativeMethods.cpSpaceSetDamping(space, value); + } + + /// + /// Speed threshold for a body to be considered idle. The default value of 0 means to let + /// the space guess a good threshold based on gravity. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public double IdleSpeedThreshold + { + get => NativeMethods.cpSpaceGetIdleSpeedThreshold(space); + set => NativeMethods.cpSpaceSetIdleSpeedThreshold(space, value); + } + + /// + /// Time a group of bodies must remain idle in order to fall asleep. Enabling sleeping also + /// implicitly enables the the contact graph. The default value of infinity disables the + /// sleeping algorithm. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public double SleepTimeThreshold + { + get => NativeMethods.cpSpaceGetSleepTimeThreshold(space); + set => NativeMethods.cpSpaceSetSleepTimeThreshold(space, value); + } + + /// + /// Amount of encouraged penetration between colliding shapes. This is used to reduce + /// oscillating contacts and keep the collision cache warm. Defaults to 0.1. If you have + /// poor simulation quality, increase this number as much as possible without allowing + /// visible amounts of overlap. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public double CollisionSlop + { + get => NativeMethods.cpSpaceGetCollisionSlop(space); + set => NativeMethods.cpSpaceSetCollisionSlop(space, value); + } + + /// + /// Determines how fast overlapping shapes are pushed apart. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public double CollisionBias + { + get => NativeMethods.cpSpaceGetCollisionBias(space); + set => NativeMethods.cpSpaceSetCollisionBias(space, value); + } + + /// + /// Number of frames that contact information should persist. Defaults to 3. There is + /// probably never a reason to change this value. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public int CollisionPersistence + { + get => (int)NativeMethods.cpSpaceGetCollisionPersistence(space); + set => NativeMethods.cpSpaceSetCollisionPersistence(space, (uint)value); + } + + /// + /// The Space provided static body for a given . + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public Body StaticBody + { + get + { + cpBody bodyHandle = NativeMethods.cpSpaceGetStaticBody(space); + cpDataPointer gcHandle = NativeMethods.cpBodyGetUserData(bodyHandle); + + if (gcHandle != IntPtr.Zero) + { + return NativeInterop.FromIntPtr(gcHandle); + } + + return new Body(bodyHandle); + } + } + + /// + /// Returns the current (or most recent) time step used with the given space. + /// Useful from callbacks if your time step is not a compile-time global. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public double CurrentTimeStep => NativeMethods.cpSpaceGetCurrentTimeStep(space); + + /// + /// Returns true from inside a callback when objects cannot be added/removed. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public bool IsLocked => NativeMethods.cpSpaceIsLocked(space) != 0; + + + // Collision Handlers + + /// + /// Create or return the existing collision handler that is called for all collisions that are + /// not handled by a more specific collision handler. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public CollisionHandler GetOrCreateDefaultCollisionHandler() + { + cpCollisionHandlerPointer collisionHandle = NativeMethods.cpSpaceAddDefaultCollisionHandler(space); + return CollisionHandler.GetOrCreate(collisionHandle); + } + + + /// + /// Create or return the existing collision handler for the specified pair of collision + /// types. If wildcard handlers are used with either of the collision types, it's the + /// responsibility of the custom handler to invoke the wildcard handlers. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public CollisionHandler GetOrCreateCollisionHandler(int typeA, int typeB) + { + uint utypeA = unchecked((uint)typeA); + uint utypeB = unchecked((uint)typeB); + + cpCollisionType collisionTypeA = new cpCollisionType(utypeA); + cpCollisionType collisionTypeB = new cpCollisionType(utypeB); + + cpCollisionHandlerPointer collisionHandle = NativeMethods.cpSpaceAddCollisionHandler(space, collisionTypeA, collisionTypeB); + return CollisionHandler.GetOrCreate(collisionHandle); + } + + + /// + /// Create or return the existing wildcard collision handler for the specified type. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public CollisionHandler GetOrCreateWildcardHandler(int type) + { + cpCollisionHandlerPointer collisionHandle = NativeMethods.cpSpaceAddWildcardHandler(space, (cpCollisionType)type); + return CollisionHandler.GetOrCreate(collisionHandle); + } + + /// + /// Add a collision shape to the simulation. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public void AddShape(Shape shape) + { + NativeMethods.cpSpaceAddShape(space, shape.Handle); + } + + /// + /// Add a rigid body to the simulation. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public void AddBody(Body body) + { + NativeMethods.cpSpaceAddBody(space, body.Handle); + } + + /// + /// Add a constraint to the simulation. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public void AddConstraint(Constraint constraint) + { + NativeMethods.cpSpaceAddConstraint(space, constraint.Handle); + } + + /// + /// Remove a collision shape from the simulation. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public void RemoveShape(Shape shape) + { + NativeMethods.cpSpaceRemoveShape(space, shape.Handle); + } + + /// + /// Remove a rigid body from the simulation. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public void RemoveBody(Body body) + { + NativeMethods.cpSpaceRemoveBody(space, body.Handle); + } + + /// + /// Remove a constraint from the simulation. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public void RemoveConstraint(Constraint constraint) + { + NativeMethods.cpSpaceRemoveConstraint(space, constraint.Handle); + } + + /// + /// Test if a collision shape has been added to the space. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public bool Contains(Shape shape) + { + return NativeMethods.cpSpaceContainsShape(space, shape.Handle) != 0; + } + + /// + /// Test if a rigid body has been added to the space. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public bool Contains(Body body) + { + return NativeMethods.cpSpaceContainsBody(space, body.Handle) != 0; + } + + /// + /// Test if a constraint has been added to the space. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public bool Contains(Constraint constraint) + { + return NativeMethods.cpSpaceContainsConstraint(space, constraint.Handle) != 0; + } + +#if __IOS__ || __TVOS__ || __WATCHOS__ || __MACCATALYST__ +#pragma warning disable CA1416 // Validate platform compatibility + [MonoPInvokeCallback(typeof(PostStepFunction))] +#pragma warning restore CA1416 // Validate platform compatibility +#endif + private static void PostStepCallBack(cpSpace handleSpace, voidptr_t handleKey, voidptr_t handleData) + { + var space = FromHandle(handleSpace); + var key = NativeInterop.FromIntPtr(handleKey); + var data = NativeInterop.FromIntPtr(handleData); + + Action callback = data.Callback; + + callback(space, key, data.Data); + + NativeInterop.ReleaseHandle(handleKey); + NativeInterop.ReleaseHandle(handleData); + } + + private static PostStepFunction postStepCallBack = PostStepCallBack; + + /// + /// Schedule a post-step callback to be called when finishes. You can + /// only register one callback per unique value for . Returns true + /// only if has never been scheduled before. It's possible to pass + /// null for if you only want to mark as + /// being used. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public bool AddPostStepCallback(Action callback, object key, object data) + { + var info = new PostStepCallbackInfo(callback, data); + + IntPtr dataHandle = NativeInterop.RegisterHandle(info); + IntPtr keyHandle = NativeInterop.RegisterHandle(key); + + return NativeMethods.cpSpaceAddPostStepCallback(space, postStepCallBack.ToFunctionPointer(), keyHandle, dataHandle) != 0; + } + +#if __IOS__ || __TVOS__ || __WATCHOS__ || __MACCATALYST__ +#pragma warning disable CA1416 // Validate platform compatibility + [MonoPInvokeCallback(typeof(SpacePointQueryFunction))] +#pragma warning restore CA1416 // Validate platform compatibility +#endif + private static void EachPointQuery(cpShape shapeHandle, Vect point, double distance, Vect gradient, voidptr_t data) + { + var list = (List)GCHandle.FromIntPtr(data).Target; + + var shape = Shape.FromHandle(shapeHandle); + var pointQuery = new PointQueryInfo(shape, point, distance, gradient); + + list.Add(pointQuery); + } + + private static SpacePointQueryFunction eachPointQuery = EachPointQuery; + + /// + /// Get the shapes within a radius of the point location that are part of this space. The + /// filter is applied to the query and follows the same rules as the collision detection. + /// If a maxDistance of 0.0 is used, the point must lie inside a shape. Negative + /// is also allowed meaning that the point must be a under a + /// certain depth within a shape to be considered a match. + /// + /// Where to check for shapes in the space. + /// Match only within this distance. + /// Only pick shapes matching the filter. + [EditorBrowsable(EditorBrowsableState.Never)] + public IReadOnlyList PointQuery(Vect point, double maxDistance, ShapeFilter filter) + { + var list = new List(); + var gcHandle = GCHandle.Alloc(list); + + NativeMethods.cpSpacePointQuery(space, point, maxDistance, filter, eachPointQuery.ToFunctionPointer(), GCHandle.ToIntPtr(gcHandle)); + + gcHandle.Free(); + return list; + } + + /// + /// Get the nearest shape within a radius of a point that is part of this space. The filter + /// is applied to the query and follows the same rules as the collision detection. If a + /// of 0.0 is used, the point must lie inside a shape. + /// Negative is also allowed, meaning that the point must be + /// under a certain depth within a shape to be considered a match. + /// + /// Where to check for collision in the space. + /// Match only within this distance. + /// Only pick shapes matching the filter. + [EditorBrowsable(EditorBrowsableState.Never)] + public PointQueryInfo PointQueryNearest(Vect point, double maxDistance, ShapeFilter filter) + { + var queryInfo = new cpPointQueryInfo(); + + cpShape shape = NativeMethods.cpSpacePointQueryNearest(space, point, maxDistance, filter, ref queryInfo); + if (shape == IntPtr.Zero) + return null; + + return PointQueryInfo.FromQueryInfo(queryInfo); + } + +#if __IOS__ || __TVOS__ || __WATCHOS__ || __MACCATALYST__ +#pragma warning disable CA1416 // Validate platform compatibility + [MonoPInvokeCallback(typeof(SpaceSegmentQueryFunction))] +#pragma warning restore CA1416 // Validate platform compatibility +#endif + private static void EachSegmentQuery(cpShape shapeHandle, Vect point, Vect normal, double alpha, voidptr_t data) + { + var list = (List)GCHandle.FromIntPtr(data).Target; + + var shape = Shape.FromHandle(shapeHandle); + var pointQuery = new SegmentQueryInfo(shape, point, normal, alpha); + + list.Add(pointQuery); + } + + private static SpaceSegmentQueryFunction eachSegmentQuery = EachSegmentQuery; + + /// + /// Get the shapes within a capsule-shaped radius of a line segment that is part of this + /// space. The filter is applied to the query and follows the same rules as the collision + /// detection. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public IReadOnlyList SegmentQuery(Vect start, Vect end, double radius, ShapeFilter filter) + { + var list = new List(); + var gcHandle = GCHandle.Alloc(list); + + NativeMethods.cpSpaceSegmentQuery(space, start, end, radius, filter, eachSegmentQuery.ToFunctionPointer(), GCHandle.ToIntPtr(gcHandle)); + + gcHandle.Free(); + return list; + } + + /// + /// Get the first shape within a capsule-shaped radius of a line segment that is part of + /// this space. The filter is applied to the query and follows the same rules as the + /// collision detection. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public SegmentQueryInfo SegmentQueryFirst(Vect start, Vect end, double radius, ShapeFilter filter) + { + var queryInfo = new cpSegmentQueryInfo(); + + cpShape shape = NativeMethods.cpSpaceSegmentQueryFirst(space, start, end, radius, filter, ref queryInfo); + if (shape == IntPtr.Zero) + return null; + + return SegmentQueryInfo.FromQueryInfo(queryInfo); + } + + +#if __IOS__ || __TVOS__ || __WATCHOS__ || __MACCATALYST__ +#pragma warning disable CA1416 // Validate platform compatibility + [MonoPInvokeCallback(typeof(SpaceBBQueryFunction))] +#pragma warning restore CA1416 // Validate platform compatibility +#endif + private static void EachBBQuery(cpShape shapeHandle, voidptr_t data) + { + var list = (List)GCHandle.FromIntPtr(data).Target; + + var shape = Shape.FromHandle(shapeHandle); + + list.Add(shape); + } + + private static SpaceBBQueryFunction eachBBQuery = EachBBQuery; + + + /// + /// Get all shapes within the axis-aligned bounding box that are part of this shape. The + /// filter is applied to the query and follows the same rules as the collision detection. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public IReadOnlyList BoundBoxQuery(BoundingBox bb, ShapeFilter filter) + { + var list = new List(); + + var gcHandle = GCHandle.Alloc(list); + + NativeMethods.cpSpaceBBQuery(space, bb, filter, eachBBQuery.ToFunctionPointer(), GCHandle.ToIntPtr(gcHandle)); + + gcHandle.Free(); + return list; + } + + /// + /// Get all bodies in the space. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public IReadOnlyList Bodies + { + get + { + int count = NativeMethods.cpSpaceGetBodyCount(space); + + if (count == 0) + return Array.Empty(); + + IntPtr ptrBodies = Marshal.AllocHGlobal(IntPtr.Size * count); + NativeMethods.cpSpaceGetBodiesUserDataArray(space, ptrBodies); + + IntPtr[] userDataArray = new IntPtr[count]; + + Marshal.Copy(ptrBodies, userDataArray, 0, count); + + Marshal.FreeHGlobal(ptrBodies); + + Body[] bodies = new Body[count]; + + for (int i = 0; i < count; i++) + { + Body b = NativeInterop.FromIntPtr(userDataArray[i]); + bodies[i] = b; + } + + return bodies; + } + } + + /// + /// Get dynamic bodies in the space. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public IReadOnlyList DynamicBodies + { + get + { + int count = NativeMethods.cpSpaceGetDynamicBodyCount(space); + + if (count == 0) + return Array.Empty(); + + IntPtr ptrBodies = Marshal.AllocHGlobal(IntPtr.Size * count); + NativeMethods.cpSpaceGetDynamicBodiesUserDataArray(space, ptrBodies); + + IntPtr[] userDataArray = new IntPtr[count]; + + Marshal.Copy(ptrBodies, userDataArray, 0, count); + + Marshal.FreeHGlobal(ptrBodies); + + Body[] bodies = new Body[count]; + + for (int i = 0; i < count; i++) + { + Body b = NativeInterop.FromIntPtr(userDataArray[i]); + bodies[i] = b; + } + + return bodies; + } + } + +#if __IOS__ || __TVOS__ || __WATCHOS__ || __MACCATALYST__ +#pragma warning disable CA1416 // Validate platform compatibility + [MonoPInvokeCallback(typeof(SpaceObjectIteratorFunction))] +#pragma warning restore CA1416 // Validate platform compatibility +#endif + private static void EachShape(cpShape shapeHandle, voidptr_t data) + { + var list = (List)GCHandle.FromIntPtr(data).Target; + + var shape = Shape.FromHandle(shapeHandle); + + list.Add(shape); + } + + private static SpaceObjectIteratorFunction eachShape = EachShape; + + /// + /// Get all shapes in the space. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public IReadOnlyList Shapes + { + get + { + var list = new List(); + + var gcHandle = GCHandle.Alloc(list); + + NativeMethods.cpSpaceEachShape(space, eachShape.ToFunctionPointer(), GCHandle.ToIntPtr(gcHandle)); + + gcHandle.Free(); + + return list; + } + } + +#if __IOS__ || __TVOS__ || __WATCHOS__ || __MACCATALYST__ +#pragma warning disable CA1416 // Validate platform compatibility + [MonoPInvokeCallback(typeof(SpaceShapeQueryFunction))] +#pragma warning restore CA1416 // Validate platform compatibility +#endif + private static void ShapeQueryCallback(cpShape shape, IntPtr pointsPointer, voidptr_t data) + { + var list = (List)GCHandle.FromIntPtr(data).Target; + + var pointSet = NativeInterop.PtrToStructure(pointsPointer); + + list.Add(ContactPointSet.FromContactPointSet(pointSet)); + } + + private static SpaceShapeQueryFunction shapeQueryCallback = ShapeQueryCallback; + + /// + /// Get all shapes in the space that are overlapping the given shape. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public IReadOnlyList ShapeQuery(Shape shape) + { + var list = new List(); + var gcHandle = GCHandle.Alloc(list); + + NativeMethods.cpSpaceShapeQuery(space, shape.Handle, shapeQueryCallback.ToFunctionPointer(), GCHandle.ToIntPtr(gcHandle)); + + gcHandle.Free(); + return list; + } + +#if __IOS__ || __TVOS__ || __WATCHOS__ || __MACCATALYST__ +#pragma warning disable CA1416 // Validate platform compatibility + [MonoPInvokeCallback(typeof(SpaceObjectIteratorFunction))] +#pragma warning restore CA1416 // Validate platform compatibility +#endif + private static void EachConstraint(cpConstraint constraintHandle, voidptr_t data) + { + var list = (List)GCHandle.FromIntPtr(data).Target; + + var constraint = Constraint.FromHandle(constraintHandle); + + list.Add(constraint); + } + + private static SpaceObjectIteratorFunction eachConstraint = EachConstraint; + + + /// + /// Get all constraints in the space. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public IReadOnlyList Constraints + { + get + { + var list = new List(); + + var gcHandle = GCHandle.Alloc(list); + + NativeMethods.cpSpaceEachConstraint(space, eachConstraint.ToFunctionPointer(), GCHandle.ToIntPtr(gcHandle)); + + gcHandle.Free(); + + return list; + } + } + + /// + /// Update the collision detection info for the static shapes in the space. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public void ReindexStatic() + { + NativeMethods.cpSpaceReindexStatic(space); + } + + /// + /// Update the collision detection data for a specific shape in the space. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public void ReindexShape(Shape shape) + { + NativeMethods.cpSpaceReindexShape(space, shape.Handle); + } + + /// + /// Update the collision detection data for all shapes attached to a body. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public void ReindexShapesForBody(Body body) + { + NativeMethods.cpSpaceReindexShapesForBody(space, body.Handle); + } + + /// + /// Switch the space to use a spatial hash as its spatial index. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public void UseSpatialHash(double dim, int count) + { + NativeMethods.cpSpaceUseSpatialHash(space, dim, count); + } + + /// + /// Update the space for the given time step. Using a fixed time step is highly recommended. + /// Doing so will increase the efficiency of the contact persistence, requiring an order of + /// magnitude fewer iterations to resolve the collisions in the usual case. It is not the + /// same to call step 10 times with a dt of 0.1, or 100 times with a dt of 0.01 even if the + /// end result is that the simulation moved forward 100 units. Performing multiple calls + /// with a smaller dt creates a more stable and accurate simulation. Therefore, it sometimes + /// makes sense to have a little for loop around the step call. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public virtual void Step(double dt) + { + NativeMethods.cpSpaceStep(space, dt); + } + + /// + /// Draw all objects in the space for debugging purposes. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public void DebugDraw(IDebugDraw debugDraw) + { + DebugDraw(debugDraw, DebugDrawFlags.All, DebugDrawColors.Default); + } + + /// + /// Draw all objects in the space for debugging purposes using flags. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public void DebugDraw(IDebugDraw debugDraw, DebugDrawFlags flags) + { + DebugDraw(debugDraw, flags, DebugDrawColors.Default); + } + + /// + /// Draw all objects in the space for debugging purposes using flags and colors. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public void DebugDraw(IDebugDraw debugDraw, DebugDrawFlags flags, DebugDrawColors colors) + { + var debugDrawOptions = new cpSpaceDebugDrawOptions(); + IntPtr debugDrawOptionsPointer = debugDrawOptions.AcquireDebugDrawOptions(debugDraw, flags, colors); + + NativeMethods.cpSpaceDebugDraw(space, debugDrawOptionsPointer); + + debugDrawOptions.ReleaseDebugDrawOptions(debugDrawOptionsPointer); + } + + } +} diff --git a/src/Tizen.NUI.Physics2D/src/public/chipmunk/Transform.cs b/src/Tizen.NUI.Physics2D/src/public/chipmunk/Transform.cs new file mode 100644 index 0000000..b5f92a3 --- /dev/null +++ b/src/Tizen.NUI.Physics2D/src/public/chipmunk/Transform.cs @@ -0,0 +1,202 @@ +/* + * Copyright (c) 2023 Codefoco (codefoco@codefoco.com) + * + * 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. + */ + +using System; +using System.ComponentModel; +using System.Runtime.InteropServices; + +#pragma warning disable IDE1006 +#pragma warning disable IDE0032 + +namespace Tizen.NUI.Physics2D.Chipmunk +{ + /// + /// Type used for 2x3 affine transforms. See wikipedia for details: + /// http://en.wikipedia.org/wiki/Affine_transformation. The properties map to the matrix in this + /// way: [[a c tx], [b d ty]]. We can't use System.Numerics.Matrix32 since it does't use + /// doubles. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + [StructLayout(LayoutKind.Sequential)] + public struct Transform : IEquatable + { + private static readonly Transform identity = new Transform(1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f); + + private double a; + private double b; + private double c; + private double d; + private double tx; + private double ty; + + /// + /// Create a matrix transformation. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public Transform(double a, double b, double c, double d, double tx, double ty) : this() + { + this.a = a; + this.b = b; + this.c = c; + this.d = d; + this.tx = tx; + this.ty = ty; + } + + /// + /// Create a transpose matrix. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public static Transform CreateTranspose(double a, double c, double tx, double b, double d, double ty) + { + return new Transform(a, b, c, d, tx, ty); + } + + /// + /// Create a translation matrix. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public static Transform CreateTranslation(Vect translate) + { + return CreateTranspose(1.0, 0.0, translate.X, 0.0, 1.0, translate.Y); + } + + /// + /// Create an identity matrix. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public static Transform Identity => identity; + + /// + /// A + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public double A { get => a; set => a = value; } + + /// + /// B + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public double B { get => b; set => b = value; } + + /// + /// C + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public double C { get => c; set => c = value; } + + /// + /// D + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public double D { get => d; set => d = value; } + + /// + /// Tx + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public double Tx { get => tx; set => tx = value; } + + /// + /// Ty + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public double Ty { get => ty; set => ty = value; } + + /// + /// Return true if all matrix values are within of each other. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public override bool Equals(object obj) + { + Transform? transform = obj as Transform?; + + if (transform == null) + return false; + + return Equals(transform.Value); + } + + /// + /// Return true if all matrix values are within of each other. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public bool Equals(Transform other) + { + return Math.Abs(a - other.a) < double.Epsilon && + Math.Abs(b - other.b) < double.Epsilon && + Math.Abs(c - other.c) < double.Epsilon && + Math.Abs(d - other.d) < double.Epsilon && + Math.Abs(tx - other.tx) < double.Epsilon && + Math.Abs(ty - other.ty) < double.Epsilon; + } + + /// + /// Get the hash code. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public override int GetHashCode() + { + var hashCode = -884009331; +#pragma warning disable RECS0025 // Non-readonly field referenced in 'GetHashCode()' + hashCode = hashCode * -1521134295 + a.GetHashCode(); + hashCode = hashCode * -1521134295 + b.GetHashCode(); + hashCode = hashCode * -1521134295 + c.GetHashCode(); + hashCode = hashCode * -1521134295 + d.GetHashCode(); + hashCode = hashCode * -1521134295 + tx.GetHashCode(); + hashCode = hashCode * -1521134295 + ty.GetHashCode(); +#pragma warning restore RECS0025 // Non-readonly field referenced in 'GetHashCode()' + return hashCode; + } + + /// + /// Return a string formatted like "(a,b|c,d|tx,ty)". + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public override string ToString() + { + return $"({a},{b}|{c},{d}|{tx},{ty})"; + } + + /// + /// Return true if all matrix values are within of each other. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public static bool operator ==(Transform transform1, Transform transform2) + { + return transform1.Equals(transform2); + } + + /// + /// Return true if all matrix values are not within of each + /// other. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public static bool operator !=(Transform transform1, Transform transform2) + { + return !(transform1 == transform2); + } + } +} + +#pragma warning restore IDE1006 +#pragma warning restore IDE0032 diff --git a/src/Tizen.NUI.Physics2D/src/public/chipmunk/Unsafe/CircleExtensions.cs b/src/Tizen.NUI.Physics2D/src/public/chipmunk/Unsafe/CircleExtensions.cs new file mode 100644 index 0000000..ec8f251 --- /dev/null +++ b/src/Tizen.NUI.Physics2D/src/public/chipmunk/Unsafe/CircleExtensions.cs @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2023 Codefoco (codefoco@codefoco.com) + * + * 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. + */ + +using System.ComponentModel; + +namespace Tizen.NUI.Physics2D.Chipmunk.Unsafe +{ + /// + /// Unsafe extension methods for the shape. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public static class CircleExtensions + { + /// + /// Change the radius of the circle shape. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public static void SetRadius(this Circle circle, double radius) + { + NativeMethods.cpCircleShapeSetRadius(circle.Handle, radius); + } + + /// + /// Change the offset of the circle shape. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public static void SetOffset(this Circle circle, Vect offset) + { + NativeMethods.cpCircleShapeSetOffset(circle.Handle, offset); + } + + } +} diff --git a/src/Tizen.NUI.Physics2D/src/public/chipmunk/Unsafe/PolygonExtensions.cs b/src/Tizen.NUI.Physics2D/src/public/chipmunk/Unsafe/PolygonExtensions.cs new file mode 100644 index 0000000..61d737d --- /dev/null +++ b/src/Tizen.NUI.Physics2D/src/public/chipmunk/Unsafe/PolygonExtensions.cs @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2023 Codefoco (codefoco@codefoco.com) + * + * 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. + */ + +using System; +using System.ComponentModel; + +namespace Tizen.NUI.Physics2D.Chipmunk.Unsafe +{ + /// + /// Unsafe extension methods for the shape. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public static class PolygonExtensions + { + /// + /// Set the vertexes of the polygon. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public static void SetVertexes(this Polygon polygon, Vect[] vertexes, Transform transform) + { + IntPtr ptrVectors = NativeInterop.StructureArrayToPtr(vertexes); + NativeMethods.cpPolyShapeSetVerts(polygon.Handle, vertexes.Length, ptrVectors, transform); + NativeInterop.FreeStructure(ptrVectors); + } + + /// + /// Set the vertexes of the polygon. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public static void SetVertexes(this Polygon polygon, Vect[] vertexes) + { + IntPtr ptrVectors = NativeInterop.StructureArrayToPtr(vertexes); + NativeMethods.cpPolyShapeSetVertsRaw(polygon.Handle, vertexes.Length, ptrVectors); + NativeInterop.FreeStructure(ptrVectors); + } + + /// + /// Set the radius of a poly shape + /// + /// + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public static void SetRadius(this Polygon polygon, double radius) + { + NativeMethods.cpPolyShapeSetRadius(polygon.Handle, radius); + } + } +} diff --git a/src/Tizen.NUI.Physics2D/src/public/chipmunk/Unsafe/SegmentExtensions.cs b/src/Tizen.NUI.Physics2D/src/public/chipmunk/Unsafe/SegmentExtensions.cs new file mode 100644 index 0000000..8035726 --- /dev/null +++ b/src/Tizen.NUI.Physics2D/src/public/chipmunk/Unsafe/SegmentExtensions.cs @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2023 Codefoco (codefoco@codefoco.com) + * + * 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. + */ + +using System.ComponentModel; + +namespace Tizen.NUI.Physics2D.Chipmunk.Unsafe +{ + /// + /// Unsafe extensions methods for the shape. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public static class SegmentExtensions + { + /// + /// Set the endpoints of a segment shape. This mutates collision shapes. Chipmunk can't get + /// velocity information on changing shapes, so the results will be unrealistic. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public static void SetEndpoints(this Segment segment, Vect a, Vect b) + { + NativeMethods.cpSegmentShapeSetEndpoints(segment.Handle, a, b); + } + + /// + /// Set the radius of a segment shape. This mutates collision shapes. Chipmunk can't get + /// velocity information on changing shapes, so the results will be unrealistic. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public static void SetRadius(this Segment segment, double radius) + { + NativeMethods.cpSegmentShapeSetRadius(segment.Handle, radius); + } + } +} diff --git a/src/Tizen.NUI.Physics2D/src/public/chipmunk/Vect.cs b/src/Tizen.NUI.Physics2D/src/public/chipmunk/Vect.cs new file mode 100644 index 0000000..41049dd --- /dev/null +++ b/src/Tizen.NUI.Physics2D/src/public/chipmunk/Vect.cs @@ -0,0 +1,437 @@ +/* + * Copyright (c) 2023 Codefoco (codefoco@codefoco.com) + * + * 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. + */ + +using System; +using System.ComponentModel; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +#pragma warning disable IDE1006 +#pragma warning disable IDE0032 + +// Chipmunk has it own Vector class, +// We can't use System.Numerics.Vector2 since is not blitable with the native Vect from Chipmunk + +namespace Tizen.NUI.Physics2D.Chipmunk +{ + /// + /// 2D Vector struct + /// + [EditorBrowsable(EditorBrowsableState.Never)] + [StructLayout(LayoutKind.Sequential)] + public struct Vect : IEquatable + { + private static readonly Vect zero = new Vect(0, 0); + + private double x; + private double y; + + /// + /// X value + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public double X + { + get => x; + set => x = value; + } + + /// + /// Y value + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public double Y + { + get => y; + set => y = value; + } + + /// + /// Create a vector. + /// + /// + /// + [EditorBrowsable(EditorBrowsableState.Never)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Vect(double x, double y) + { + this.x = x; + this.y = y; + } + + /// + /// Return true if both objects are within of each other. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public override bool Equals(object obj) + { + Vect? vect = obj as Vect?; + + if (vect == null) + return false; + + return this == vect.Value; + } + + /// + /// Get the hash code. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public override int GetHashCode() + { +#pragma warning disable RECS0025 // Non-readonly field referenced in 'GetHashCode()' + return (x.GetHashCode() << 16) ^ y.GetHashCode(); +#pragma warning restore RECS0025 // Non-readonly field referenced in 'GetHashCode()' + } + + /// + /// Return true if both objects are within of each other. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public bool Equals(Vect other) + { + return this == other; + } + + /// + /// Return a string formatted like "(x,y)". + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public override string ToString() + { + return $"({x},{y})"; + } + + /// + /// Return true if both objects are within of each other. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public static bool operator ==(Vect a, Vect b) + { + return Math.Abs(b.x - a.x) <= double.Epsilon && + Math.Abs(b.y - a.y) <= double.Epsilon; + } + + /// + /// Return true if both objects are not within of each other. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public static bool operator !=(Vect a, Vect b) + { + return !(a == b); + } + + /// + /// Add two vectors. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vect operator +(Vect a, Vect b) + { + return new Vect(a.x + b.x, a.y + b.y); + } + + /// + /// Subtract two vectors. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vect operator -(Vect a, Vect b) + { + return new Vect(a.x - b.x, a.y - b.y); + } + + /// + /// Negate a vector. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vect operator -(Vect a) + { + return new Vect(-a.x, -a.y); + } + + /// + /// Scalar multiplication. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vect operator *(Vect a, double s) + { + return new Vect(a.x * s, a.y * s); + } + + /// + /// Scalar division. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vect operator /(Vect a, double s) + { + return new Vect(a.x / s, a.y / s); + } + + /// + /// Scalar multiplication. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vect operator *(double s, Vect a) + { + return new Vect(a.x * s, a.y * s); + } + + /// + /// Scalar division. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vect operator /(double s, Vect a) + { + return new Vect(a.x / s, a.y / s); + } + + /// + /// Vector dot product. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public double Dot(Vect v2) + { + return x * v2.x + y * v2.y; + } + + /// + /// 2D vector cross product analog. The cross product of 2D vectors results in a 3D vector + /// with only a z component. This function returns the magnitude of the z value. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public double Cross(Vect v2) + { + return x * v2.y - y * v2.x; + } + + /// + /// Returns a perpendicular vector (-90 degree rotation). + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public Vect Perpendicurlar => new Vect(-y, x); + + /// + /// Returns the vector projection of v1 onto v2. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Vect Project(Vect v2) + { + return v2 * Dot(v2) / v2.Dot(v2); + } + + /// + /// Returns the unit length vector for the given angle (in radians). + /// + [EditorBrowsable(EditorBrowsableState.Never)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vect ForAngle(double angle) + { + return new Vect(Math.Cos(angle), Math.Sin(angle)); + } + + /// + /// Returns the angular direction v is pointing in (in radians). + /// + [EditorBrowsable(EditorBrowsableState.Never)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public double ToAngle() + { + return Math.Atan2(y, x); + } + + /// + /// Uses complex number multiplication to rotate v1 by v2. Scaling will occur if v1 is not a + /// unit vector. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Vect Rotate(Vect v2) + { + return new Vect(x * v2.x - y * v2.y, x * v2.y + y * v2.x); + } + + /// + /// Inverse of Rotate(). + /// + [EditorBrowsable(EditorBrowsableState.Never)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Vect Unrotate(Vect v2) + { + return new Vect(x * v2.x + y * v2.y, y * v2.x - x * v2.y); + } + + /// + /// Returns the squared length of v. Faster than when you only need to + /// compare lengths. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public double LengthSquared() => Dot(this); + + /// + /// Returns the length of v. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public double Length() + { + return Math.Sqrt(Dot(this)); + } + + /// + /// Linearly interpolate between this and . + /// + [EditorBrowsable(EditorBrowsableState.Never)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Vect Lerp(Vect v2, double t) + { + return this * (1.0 - t) + v2 * t; + } + + /// + /// Returns a normalized copy. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Vect Normalize() + { + return this * (1.0 / (Length() + double.Epsilon)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + static double Clamp(double value, double min, double max) + { + if (value < min) + { + return min; + } + if (value > max) + { + return max; + } + + return value; + } + + /// + /// Spherical linear interpolation between current position and based + /// on . + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public Vect SLerp(Vect v2, double t) + { + double dot = Normalize().Dot(v2.Normalize()); + double omega = Math.Acos(Clamp(dot, -1.0f, 1.0f)); + + if (omega < 1e-3) + { + // If the angle between two vectors is very small, lerp instead to avoid precision issues. + return Lerp(v2, t); + } + + double denom = 1.0 / Math.Sin(omega); + return (this * Math.Sin((1.0f - t) * omega) * denom) + v2 * Math.Sin(t * omega) * denom; + } + + /// + /// Spherical linear interpolation between current position towards by + /// no more than angle radians. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public Vect SLerpConst(Vect v2, double a) + { + double dot = Normalize().Dot(v2.Normalize()); + double omega = Math.Acos(Clamp(dot, -1.0f, 1.0f)); + + return SLerp(v2, Math.Min(a, omega) / omega); + } + + /// + /// Clamp the magnitude to the given length. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + [EditorBrowsable(EditorBrowsableState.Never)] + public Vect Clamp(double length) + { + return Dot(this) > length * length ? Normalize() * length : this; + } + + /// + /// Linearly interpolate between the current position towards by + /// distance . + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public Vect LerpConst(Vect v2, double d) + { + return this + (v2 - this).Clamp(d); + } + + /// + /// Return the distance between this and . + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + [EditorBrowsable(EditorBrowsableState.Never)] + public double Distance(Vect v2) + { + return (this - v2).Length(); + } + + /// + /// Return the squared distance between current position and . Faster + /// than when you only need to compare distances. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + [EditorBrowsable(EditorBrowsableState.Never)] + public double DistanceSquare(Vect v2) + { + return (this - v2).LengthSquared(); + } + + /// + /// Return true if the distance between current position and is less + /// than . + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public bool Near(Vect v2, double distance) + { + return DistanceSquare(v2) < distance * distance; + } + + /// + /// (0, 0) Vector. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public static Vect Zero => zero; + } +} + +#pragma warning restore IDE1006 +#pragma warning restore IDE0032 diff --git a/test/Tizen.NUI.Physics2D.Sample/Physics2DSample.cs b/test/Tizen.NUI.Physics2D.Sample/Physics2DSample.cs new file mode 100644 index 0000000..e790dec --- /dev/null +++ b/test/Tizen.NUI.Physics2D.Sample/Physics2DSample.cs @@ -0,0 +1,216 @@ +/* +* Copyright (c) 2023 Samsung Electronics Co., Ltd. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* +*/ + +using System; +using System.Runtime.InteropServices; +using System.Runtime.CompilerServices; +using System.Text; +using System.Linq; +using Tizen.NUI.Physics2D.Chipmunk; + +// Tests the basic functionality of the Chipmunk2D physics engine without the need of any rendering. +// It sets up a 2D physics simulation with a dynamic circle dropping to the top of two static segments +// representing the ground and bouncing back. The simulation is run for a fixed number of time steps, +// and the position of the circle body is printed at each step to verify the correctness of the physics +// simulation. + +class Physics2DSample +{ + public Physics2DSample() + { + // Create a space for physics simulation + var space = new Space(); + + // Set up gravity along the Y-axis (negative value for downward) + var gravity = new Vect(0, -100); + space.Gravity = gravity; + + // Create two static bodies (static bodies do not move) with shapes (segments) to form the ground + var groundBody1 = new Body(BodyType.Static); + var groundBody2 = new Body(BodyType.Static); + + // Add the body to the space + space.AddBody(groundBody1); + space.AddBody(groundBody2); + + var groundStart = new Vect(-1000, 0); // Start point of the ground + var groundEnd = new Vect(1000, 0); // End point of the ground + + var groundShape1 = new Segment(groundBody1, groundStart, groundEnd, 0); + var groundShape2 = new Segment(groundBody2, groundStart, groundEnd, 0); + + groundShape1.CollisionType = 0; + groundShape2.CollisionType = 1; + + groundShape1.Elasticity = 0.85f; + groundShape2.Elasticity = 0.85f; + + // Add the shapes to the space + space.AddShape(groundShape1); + space.AddShape(groundShape2); + + // Create a dynamic body with a circle shape + var radius = 20.0; + var mass = 1.0; + var moment = Circle.MomentForCircle(mass, 0, radius, Vect.Zero); + + // Set initial position for the circle + var circleBody = new Body(mass, moment); + circleBody.Position = new Vect(0, 50); + + // Add the body to the space + space.AddBody(circleBody); + + // Create a circle shape + var circleShape = new Circle(circleBody, radius, Vect.Zero); + circleShape.CollisionType = 2; + circleShape.Elasticity = 0.85f; + + // Add the circle shape to the space + space.AddShape(circleShape); + + // Detect the collision between the circle and the ground + CollisionHandler handler = space.GetOrCreateCollisionHandler(0, 2); + handler.Data = new StringBuilder(); + + handler.Begin = (arbiterHandle, spaceHandle, userData) => + { + StringBuilder builder = (StringBuilder)userData; + _ = builder.Append("Begin -> "); + + Console.WriteLine("CollisionHandler::" + handler.Data.ToString()); + }; + + handler.PreSolve = (arbiterHandle, spaceHandle, userData) => + { + StringBuilder builder = (StringBuilder)userData; + _ = builder.Append("PreSolve -> "); + + Console.WriteLine("CollisionHandler::" + handler.Data.ToString()); + + return true; + }; + + handler.PostSolve = (arbiterHandle, spaceHandle, userData) => + { + StringBuilder builder = (StringBuilder)userData; + _ = builder.Append("PostSolve -> "); + + Console.WriteLine("CollisionHandler::" + handler.Data.ToString()); + }; + + handler.Separate = (arbiterHandle, spaceHandle, userData) => + { + StringBuilder builder = (StringBuilder)userData; + _ = builder.Append("Separate -> "); + + Console.WriteLine("CollisionHandler::" + handler.Data.ToString()); + }; + + + // Simulate the physics for some time steps + var numSteps = 60; // Number of simulation steps + var timeStep = 1.0 / 60.0; // Time step for each simulation step (60 FPS) + + // Set the velocity of the circle body to make it move to the right + circleBody.Velocity = new Vect(100, 0); // Velocity of (100, 0) along the X-axis + + for (int i = 0; i < numSteps; ++i) + { + space.Step(timeStep); + + // Print the position of the circle body during simulation + var position = circleBody.Position; + Console.WriteLine("Step " + i + " - Circle Position: (" + position.X + ", " + position.Y + ")"); + } + + // Make a point query on a shape + { + circleShape.Filter = new ShapeFilter((UIntPtr)10, 1, 5); + ShapeFilter filter = circleShape.Filter; + Console.WriteLine("ShapeFilter: " + filter.Group + ", " + filter.Categories + ", " + filter.Mask); + + var body = new Body(1, 1.66); + var shape = new Box(body, 2, 2, 0); + + PointQueryInfo point = shape.PointQuery(new Vect(3, 4)); + Console.WriteLine("Shape PointQuery: Distance: " + point.Distance + ", Point: " + point.Point + ", Gradient.X: " + point.Gradient.X + ", Gradient.Y: " + point.Gradient.Y); + + shape.Dispose(); + body.Dispose(); + } + + // Make a point query on a space + { + var mySpace = new Space(); + var body = new Body(1, 1.66); + var shape = new Box(body, 100, 100, 0); + + body.Position = new Vect(0, 0); + + PointQueryInfo[] infos = mySpace.PointQuery(body.Position, 10.0, ShapeFilter.FILTER_ALL).ToArray(); + Console.WriteLine("Space PointQuery: infos.Length: " + infos.Length); + + mySpace.AddBody(body); + mySpace.AddShape(shape); + + infos = mySpace.PointQuery(body.Position, 10.0, ShapeFilter.FILTER_ALL).ToArray(); + Console.WriteLine("Space PointQuery: infos.Length: " + infos.Length); + + if (infos.Length > 0 && shape == infos[0].Shape) + { + Console.WriteLine("Space PointQuery: The shape matches"); + } + + PointQueryInfo info = space.PointQueryNearest(new Vect(0, 0), 100.0, ShapeFilter.FILTER_ALL); + + if (info == null || info.Shape == null) + { + Console.WriteLine("Space PointQueryNearest: No shape is found"); + } + else + { + Console.WriteLine("Shape PointQueryNearest: Distance: " + info.Distance + ", Point: " + info.Point + ", Gradient.X: " + info.Gradient.X + ", Gradient.Y: " + info.Gradient.Y + ", Body position: " + info.Shape.Body.Position); + } + + shape.Dispose(); + body.Dispose(); + mySpace.Dispose(); + } + + // Clean up + groundShape1.Dispose(); + groundShape2.Dispose(); + circleShape.Dispose(); + + groundBody1.Dispose(); + groundBody2.Dispose(); + circleBody.Dispose(); + + space.Dispose(); + } + + /// + /// The main entry point for the application. + /// + [STAThread] // Forces app to use one thread to access NUI + static void Main(string[] args) + { + Physics2DSample example = new Physics2DSample(); + } +} + diff --git a/test/Tizen.NUI.Physics2D.Sample/Tizen.NUI.Physics2D.Sample.csproj b/test/Tizen.NUI.Physics2D.Sample/Tizen.NUI.Physics2D.Sample.csproj new file mode 100644 index 0000000..b3cedf0 --- /dev/null +++ b/test/Tizen.NUI.Physics2D.Sample/Tizen.NUI.Physics2D.Sample.csproj @@ -0,0 +1,22 @@ + + + net6.0 + Exe + Physics2DSample + + + portable + + + None + + + + + + + + + True + + diff --git a/test/Tizen.NUI.Physics2D.Sample/tizen-manifest.xml b/test/Tizen.NUI.Physics2D.Sample/tizen-manifest.xml new file mode 100644 index 0000000..ce556b8 --- /dev/null +++ b/test/Tizen.NUI.Physics2D.Sample/tizen-manifest.xml @@ -0,0 +1,13 @@ + + + + + + NUI.png + + + + + + +