[NUI.Physics2D] Adding Dali/Chipmunk interop
authorDavid Steele <david.steele@samsung.com>
Mon, 11 Sep 2023 20:23:20 +0000 (21:23 +0100)
committerbshsqa <32317749+bshsqa@users.noreply.github.com>
Thu, 14 Sep 2023 10:40:33 +0000 (19:40 +0900)
Adds Tizen.NUI.Physics2D.PhysicsAdaptor,
Tizen.NUI.Physics2D.PhysicsActor and
Tizen.NUI.Physics2D.ScopedAccessor classes.

These wrap the DALi physics classes in dali-toolkit; which run
the physics integration thread in the Update thread (using the
FrameCallback natively). They offer basic APIs for attaching
Views to Chipmunk.Body physics objects, so that they can
be rendered.

14 files changed:
src/Tizen.NUI.Physics2D/Tizen.NUI.Physics2D.csproj
src/Tizen.NUI.Physics2D/src/internal/interop/Interop.Actor.cs [new file with mode: 0644]
src/Tizen.NUI.Physics2D/src/internal/interop/Interop.Adaptor.cs [new file with mode: 0644]
src/Tizen.NUI.Physics2D/src/internal/interop/Interop.Libraries.cs [new file with mode: 0644]
src/Tizen.NUI.Physics2D/src/internal/interop/Interop.World.cs [new file with mode: 0644]
src/Tizen.NUI.Physics2D/src/public/chipmunk/Body.cs
src/Tizen.NUI.Physics2D/src/public/chipmunk/Space.cs
src/Tizen.NUI.Physics2D/src/public/chipmunk/SpaceRef.cs [new file with mode: 0644]
src/Tizen.NUI.Physics2D/src/public/wrapper/PhysicsActor.cs [new file with mode: 0644]
src/Tizen.NUI.Physics2D/src/public/wrapper/PhysicsAdaptor.cs [new file with mode: 0644]
src/Tizen.NUI.Physics2D/src/public/wrapper/ScopedPhysicsAccessor.cs [new file with mode: 0644]
src/Tizen.NUI/src/internal/Common/FriendAssembly.cs
test/Tizen.NUI.Physics2D.Sample/Physics2DSample.cs
test/Tizen.NUI.Physics2D.Sample/res/images/blocks-ball.png [new file with mode: 0644]

index ab51d11..0b35f62 100755 (executable)
@@ -11,7 +11,9 @@
   </ItemGroup>
 
   <ItemGroup>
-    <Folder Include="chipmunk\" />
+    <Folder Include="chipmunk" />
+    <Folder Include="interop" />
+    <Folder Include="wrapper" />
   </ItemGroup>
 
 </Project>
diff --git a/src/Tizen.NUI.Physics2D/src/internal/interop/Interop.Actor.cs b/src/Tizen.NUI.Physics2D/src/internal/interop/Interop.Actor.cs
new file mode 100644 (file)
index 0000000..163c8e4
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * 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 Tizen.NUI.Physics2D.Chipmunk;
+
+namespace Tizen.NUI.Physics2D
+{
+    internal static partial class Interop
+    {
+        internal static class Actor
+        {
+            [DllImport(Libraries.Physics2D, EntryPoint = "CSharp_Dali_PhysicsActor_New")]
+            internal static extern global::System.IntPtr PhysicsActorNew(HandleRef actor, IntPtr Body, HandleRef adaptor);
+
+            [DllImport(Libraries.Physics2D, EntryPoint = "CSharp_Dali_new_PhysicsActor__SWIG_0")]
+            internal static extern global::System.IntPtr NewPhysicsActor();
+
+            [DllImport(Libraries.Physics2D, EntryPoint = "CSharp_Dali_new_PhysicsActor__SWIG_1")]
+            internal static extern global::System.IntPtr NewPhysicsActor(HandleRef rhs);
+
+            [DllImport(Libraries.Physics2D, EntryPoint = "CSharp_Dali_PhysicsActor_DownCast")]
+            internal static extern global::System.IntPtr DownCast(HandleRef handle);
+
+            [DllImport(Libraries.Physics2D, EntryPoint = "CSharp_Dali_delete_PhysicsActor")]
+            internal static extern void DeletePhysicsActor(HandleRef handle);
+
+            [DllImport(Libraries.Physics2D, EntryPoint = "CSharp_Dali_PhysicsActor_Assign")]
+            internal static extern global::System.IntPtr Assign(HandleRef destination, HandleRef source);
+
+            [DllImport(Libraries.Physics2D, EntryPoint = "CSharp_Dali_PhysicsActor_GetId")]
+            internal static extern uint GetId(HandleRef handle);
+
+            [DllImport(Libraries.Physics2D, EntryPoint = "CSharp_Dali_PhysicsActor_GetBody")]
+            internal static extern global::System.IntPtr GetBody(HandleRef handle);
+
+            [DllImport(Libraries.Physics2D, EntryPoint = "CSharp_Dali_PhysicsActor_AsyncSetPhysicsPosition")]
+            internal static extern void AsyncSetPhysicsPosition(HandleRef handle, HandleRef position);
+
+            [DllImport(Libraries.Physics2D, EntryPoint = "CSharp_Dali_PhysicsActor_AsyncSetPhysicsRotation")]
+            internal static extern void AsyncSetPhysicsRotation(HandleRef handle, HandleRef rotation);
+
+            [DllImport(Libraries.Physics2D, EntryPoint = "CSharp_Dali_PhysicsActor_GetPhysicsPosition")]
+            internal static extern global::System.IntPtr GetPhysicsPosition(HandleRef handle);
+
+            [DllImport(Libraries.Physics2D, EntryPoint = "CSharp_Dali_PhysicsActor_GetPhysicsRotation")]
+            internal static extern global::System.IntPtr GetPhysicsRotation(HandleRef handle);
+
+            [DllImport(Libraries.Physics2D, EntryPoint = "CSharp_Dali_PhysicsActor_GetActorPosition")]
+            internal static extern global::System.IntPtr GetActorPosition(HandleRef handle);
+
+            [DllImport(Libraries.Physics2D, EntryPoint = "CSharp_Dali_PhysicsActor_GetActorRotation")]
+            internal static extern global::System.IntPtr GetActorRotation(HandleRef handle);
+        }
+    }
+}
diff --git a/src/Tizen.NUI.Physics2D/src/internal/interop/Interop.Adaptor.cs b/src/Tizen.NUI.Physics2D/src/internal/interop/Interop.Adaptor.cs
new file mode 100644 (file)
index 0000000..b8e1a94
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+ * 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 Tizen.NUI.Physics2D.Chipmunk;
+
+namespace Tizen.NUI.Physics2D
+{
+    internal static partial class Interop
+    {
+        internal static class Adaptor
+        {
+            [DllImport(Libraries.Physics2D, EntryPoint = "CSharp_Dali_PhysicsAdaptor_New")]
+            internal static extern global::System.IntPtr PhysicsAdaptorNew(HandleRef matrix, HandleRef size);
+
+            [DllImport(Libraries.Physics2D, EntryPoint = "CSharp_Dali_new_PhysicsAdaptor__SWIG_0")]
+            internal static extern global::System.IntPtr NewPhysicsAdaptor();
+
+            [DllImport(Libraries.Physics2D, EntryPoint = "CSharp_Dali_new_PhysicsAdaptor__SWIG_1")]
+            internal static extern global::System.IntPtr NewPhysicsAdaptor(HandleRef rhs);
+
+            [DllImport(Libraries.Physics2D, EntryPoint = "CSharp_Dali_delete_PhysicsAdaptor")]
+            internal static extern void DeletePhysicsAdaptor(HandleRef handle);
+
+            [DllImport(Libraries.Physics2D, EntryPoint = "CSharp_Dali_PhysicsAdaptor_DownCast")]
+            internal static extern global::System.IntPtr DownCast(HandleRef handle);
+
+            [DllImport(Libraries.Physics2D, EntryPoint = "CSharp_Dali_PhysicsAdaptor_Assign")]
+            internal static extern global::System.IntPtr Assign(HandleRef destination, HandleRef source);
+
+            [DllImport(Libraries.Physics2D, EntryPoint = "CSharp_Dali_PhysicsAdaptor_SetTimestep")]
+            internal static extern void SetTimestep(HandleRef adaptor, float timestep);
+
+            [DllImport(Libraries.Physics2D, EntryPoint = "CSharp_Dali_PhysicsAdaptor_GetTimestep")]
+            internal static extern float GetTimestep(HandleRef adaptor);
+
+            [DllImport(Libraries.Physics2D, EntryPoint = "CSharp_Dali_PhysicsAdaptor_CreateDebugLayer")]
+            internal static extern global::System.IntPtr CreateDebugLayer(HandleRef adaptor, HandleRef window);
+            // Layer
+
+            [DllImport(Libraries.Physics2D, EntryPoint = "CSharp_Dali_PhysicsAdaptor_TranslateToPhysicsSpace_1")]
+            internal static extern global::System.IntPtr TranslatePositionToPhysicsSpace(HandleRef adaptor, HandleRef position);
+            // Vector3
+            [DllImport(Libraries.Physics2D, EntryPoint = "CSharp_Dali_PhysicsAdaptor_TranslateToPhysicsSpace_2")]
+            internal static extern global::System.IntPtr TranslateRotationToPhysicsSpace(HandleRef adaptor, HandleRef rotation);
+            // Quaternion
+
+            [DllImport(Libraries.Physics2D, EntryPoint = "CSharp_Dali_PhysicsAdaptor_TranslateFromPhysicsSpace_1")]
+            internal static extern global::System.IntPtr TranslatePositionFromPhysicsSpace(HandleRef adaptor, HandleRef position);
+            // Vector3
+            [DllImport(Libraries.Physics2D, EntryPoint = "CSharp_Dali_PhysicsAdaptor_TranslateFromPhysicsSpace_2")]
+            internal static extern global::System.IntPtr TranslateRotationFromPhysicsSpace(HandleRef adaptor, HandleRef rotation);
+            // Quaternion
+
+            [DllImport(Libraries.Physics2D, EntryPoint = "CSharp_Dali_PhysicsAdaptor_ConvertVectorToPhysicsSpace")]
+            internal static extern global::System.IntPtr ConvertVectorToPhysicsSpace(HandleRef adaptor, HandleRef vector);
+            // Vector3
+            [DllImport(Libraries.Physics2D, EntryPoint = "CSharp_Dali_PhysicsAdaptor_ConvertVectorFromPhysicsSpace")]
+            internal static extern global::System.IntPtr ConvertVectorFromPhysicsSpace(HandleRef adaptor, HandleRef vector);
+            // Vector3
+
+            [DllImport(Libraries.Physics2D, EntryPoint = "CSharp_Dali_PhysicsAdaptor_SetTransformAndSize")]
+            internal static extern void SetTransformAndSize(HandleRef adaptor, HandleRef transform, HandleRef size);
+
+            [DllImport(Libraries.Physics2D, EntryPoint = "CSharp_Dali_PhysicsAdaptor_SetIntegrationState")]
+            internal static extern void SetIntegrationState(HandleRef adaptor, int integrationState);
+
+            [DllImport(Libraries.Physics2D, EntryPoint = "CSharp_Dali_PhysicsAdaptor_GetIntegrationState")]
+            internal static extern int GetIntegrationState(HandleRef adaptor);
+
+            [DllImport(Libraries.Physics2D, EntryPoint = "CSharp_Dali_PhysicsAdaptor_SetDebugState")]
+            internal static extern void SetDebugState(HandleRef adaptor, int integrationState);
+
+            [DllImport(Libraries.Physics2D, EntryPoint = "CSharp_Dali_PhysicsAdaptor_GetDebugState")]
+            internal static extern int GetDebugState(HandleRef adaptor);
+
+            [DllImport(Libraries.Physics2D, EntryPoint = "CSharp_Dali_PhysicsAdaptor_AddActorBody")]
+            internal static extern global::System.IntPtr AddActorBody(HandleRef adaptor, HandleRef actor, global::System.IntPtr body);
+            // PhysicsActor
+            [DllImport(Libraries.Physics2D, EntryPoint = "CSharp_Dali_PhysicsAdaptor_RemoveActorBody")]
+            internal static extern void RemoveActorBody(HandleRef adaptor, HandleRef physicsActor);
+
+            [DllImport(Libraries.Physics2D, EntryPoint = "CSharp_Dali_PhysicsAdaptor_GetPhysicsActor")]
+            internal static extern global::System.IntPtr GetPhysicsActor(HandleRef adaptor, global::System.IntPtr body);
+            // PhysicsActor
+
+            [DllImport(Libraries.Physics2D, EntryPoint = "CSharp_Dali_PhysicsAdaptor_GetRootActor")]
+            internal static extern global::System.IntPtr GetRootActor(HandleRef adaptor);
+            // Actor
+
+            [DllImport(Libraries.Physics2D, EntryPoint = "CSharp_Dali_PhysicsAdaptor_BuildPickingRay")]
+            internal static extern void BuildPickingRay(HandleRef adaptor, HandleRef origin, HandleRef direction,
+                                                        HandleRef rayFromWorld, HandleRef rayToWorld);
+
+            [DllImport(Libraries.Physics2D, EntryPoint = "CSharp_Dali_PhysicsAdaptor_ProjectPoint")]
+            internal static extern global::System.IntPtr ProjectPoint(HandleRef adaptor, HandleRef origin, HandleRef direction, float distance);
+            // Vector3
+
+            [DllImport(Libraries.Physics2D, EntryPoint = "CSharp_Dali_PhysicsAdaptor_CreateSyncPoint")]
+            internal static extern void CreateSyncPoint(HandleRef adaptor);
+
+            [DllImport(Libraries.Physics2D, EntryPoint = "CSharp_Dali_PhysicsAdaptor_GetPhysicsWorld")]
+            internal static extern global::System.IntPtr GetPhysicsWorld(HandleRef adaptor);
+        }
+    }
+}
diff --git a/src/Tizen.NUI.Physics2D/src/internal/interop/Interop.Libraries.cs b/src/Tizen.NUI.Physics2D/src/internal/interop/Interop.Libraries.cs
new file mode 100644 (file)
index 0000000..b9e984e
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2023 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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.
+ */
+
+namespace Tizen.NUI.Physics2D
+{
+    internal static partial class Interop
+    {
+        internal static partial class Libraries
+        {
+#if __MACOS__
+            public const string Physics2D = "libdali2-csharp-binder-physics-2d.dylib";
+#else
+            public const string Physics2D = "libdali2-csharp-binder-physics-2d.so";
+#endif
+        }
+    }
+}
diff --git a/src/Tizen.NUI.Physics2D/src/internal/interop/Interop.World.cs b/src/Tizen.NUI.Physics2D/src/internal/interop/Interop.World.cs
new file mode 100644 (file)
index 0000000..29aea3b
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * 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 Tizen.NUI.Physics2D.Chipmunk;
+
+namespace Tizen.NUI.Physics2D
+{
+    internal static partial class Interop
+    {
+        internal static partial class World
+        {
+            [DllImport(Libraries.Physics2D, EntryPoint = "CSharp_Dali_PhysicsWorld_Lock")]
+            internal static extern void Lock(global::System.IntPtr world);
+
+            [DllImport(Libraries.Physics2D, EntryPoint = "CSharp_Dali_PhysicsWorld_Unlock")]
+            internal static extern void Unlock(global::System.IntPtr world);
+
+            [DllImport(Libraries.Physics2D, EntryPoint = "CSharp_Dali_PhysicsWorld_GetNative")]
+            internal static extern global::System.IntPtr GetNative(global::System.IntPtr world);
+
+            [DllImport(Libraries.Physics2D, EntryPoint = "CSharp_Dali_PhysicsWorld_HitTest")]
+            internal static extern global::System.IntPtr HitTest(global::System.IntPtr world, HandleRef rayFromWorld,
+                                                                 HandleRef rayToWorld, Chipmunk.ShapeFilter nativeFilter,
+                                                                 HandleRef localPivot, out float distanceFromCamera);
+        }
+    }
+}
index 850b208..647c0ef 100644 (file)
@@ -7,10 +7,10 @@
  * 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
@@ -247,7 +247,7 @@ namespace Tizen.NUI.Physics2D.Chipmunk
 
         /// <summary>
         /// Mass of the rigid body. Mass does not have to be expressed in any particular units, but
-        /// relative masses should be consistent. 
+        /// relative masses should be consistent.
         /// </summary>
         [EditorBrowsable(EditorBrowsableState.Never)]
         public double Mass
@@ -259,7 +259,7 @@ namespace Tizen.NUI.Physics2D.Chipmunk
         /// <summary>
         /// 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. 
+        /// MomentFor*() functions to estimate it, or the physics may behave strangely.
         /// </summary>
         [EditorBrowsable(EditorBrowsableState.Never)]
         public double Moment
index df8c661..db27ebd 100755 (executable)
@@ -7,10 +7,10 @@
  * 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
@@ -77,6 +77,12 @@ namespace Tizen.NUI.Physics2D.Chipmunk
             RegisterUserData();
         }
 
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        internal static Space NativeSpace(cpSpace handle)
+        {
+            return new Space(handle);
+        }
+
         /// <summary>
         /// Destroys and frees.
         /// </summary>
@@ -169,7 +175,7 @@ namespace Tizen.NUI.Physics2D.Chipmunk
         }
 
         /// <summary>
-        /// Gravity to pass to rigid bodies when integrating velocity. 
+        /// Gravity to pass to rigid bodies when integrating velocity.
         /// </summary>
         [EditorBrowsable(EditorBrowsableState.Never)]
         public Vect Gravity
@@ -193,7 +199,7 @@ namespace Tizen.NUI.Physics2D.Chipmunk
 
         /// <summary>
         /// 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. 
+        /// the space guess a good threshold based on gravity.
         /// </summary>
         [EditorBrowsable(EditorBrowsableState.Never)]
         public double IdleSpeedThreshold
@@ -205,7 +211,7 @@ namespace Tizen.NUI.Physics2D.Chipmunk
         /// <summary>
         /// 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. 
+        /// sleeping algorithm.
         /// </summary>
         [EditorBrowsable(EditorBrowsableState.Never)]
         public double SleepTimeThreshold
@@ -218,7 +224,7 @@ namespace Tizen.NUI.Physics2D.Chipmunk
         /// 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. 
+        /// visible amounts of overlap.
         /// </summary>
         [EditorBrowsable(EditorBrowsableState.Never)]
         public double CollisionSlop
@@ -335,7 +341,7 @@ namespace Tizen.NUI.Physics2D.Chipmunk
         }
 
         /// <summary>
-        /// Add a rigid body to the simulation. 
+        /// Add a rigid body to the simulation.
         /// </summary>
         [EditorBrowsable(EditorBrowsableState.Never)]
         public void AddBody(Body body)
diff --git a/src/Tizen.NUI.Physics2D/src/public/chipmunk/SpaceRef.cs b/src/Tizen.NUI.Physics2D/src/public/chipmunk/SpaceRef.cs
new file mode 100644 (file)
index 0000000..9313ff1
--- /dev/null
@@ -0,0 +1,776 @@
+/*
+ * 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
+{
+    /// <summary>
+    /// Weak reference to a Space.
+    /// Gives access to the Native cpSpace API without enforcing
+    /// ownership of the space (which may instead be owned by the
+    /// rendering library)
+    /// </summary>
+    [EditorBrowsable(EditorBrowsableState.Never)]
+    public class SpaceRef
+    {
+#pragma warning disable IDE0032
+        private readonly cpSpace space;
+#pragma warning restore IDE0032
+
+        /// <summary>
+        /// The space reference constructor can only be called from
+        /// Tizen.NUI.Physics2D.ScopedPhysicsAccessor.GetNative().
+        /// It is not intended to be generated by the developer.
+        /// </summary>
+        /// <param name="handle"></param>
+        internal SpaceRef(cpSpace handle)
+        {
+            space = handle;
+        }
+
+        /// <summary>
+        /// Get a Space object from native cpSpace handle.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        private static Space FromHandle(cpSpace space)
+        {
+            cpDataPointer handle = NativeMethods.cpSpaceGetUserData(space);
+            return NativeInterop.FromIntPtr<Space>(handle);
+        }
+
+
+        // Properties
+
+        /// <summary>
+        /// Arbitrary user data.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public object Data { get; set; }
+
+        /// <summary>
+        /// Number of iterations to use in the impulse solver to solve contacts and other
+        /// constraints.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public int Iterations
+        {
+            get => NativeMethods.cpSpaceGetIterations(space);
+            set => NativeMethods.cpSpaceSetIterations(space, value);
+        }
+
+        /// <summary>
+        /// Gravity to pass to rigid bodies when integrating velocity.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public Vect Gravity
+        {
+            get => NativeMethods.cpSpaceGetGravity(space);
+            set => NativeMethods.cpSpaceSetGravity(space, value);
+        }
+
+        /// <summary>
+        /// 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 <see cref="DampedSpring"/> and <see cref="DampedRotarySpring"/>.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public double Damping
+        {
+            get => NativeMethods.cpSpaceGetDamping(space);
+            set => NativeMethods.cpSpaceSetDamping(space, value);
+        }
+
+        /// <summary>
+        /// 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.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public double IdleSpeedThreshold
+        {
+            get => NativeMethods.cpSpaceGetIdleSpeedThreshold(space);
+            set => NativeMethods.cpSpaceSetIdleSpeedThreshold(space, value);
+        }
+
+        /// <summary>
+        /// 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.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public double SleepTimeThreshold
+        {
+            get => NativeMethods.cpSpaceGetSleepTimeThreshold(space);
+            set => NativeMethods.cpSpaceSetSleepTimeThreshold(space, value);
+        }
+
+        /// <summary>
+        /// 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.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public double CollisionSlop
+        {
+            get => NativeMethods.cpSpaceGetCollisionSlop(space);
+            set => NativeMethods.cpSpaceSetCollisionSlop(space, value);
+        }
+
+        /// <summary>
+        /// Determines how fast overlapping shapes are pushed apart.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public double CollisionBias
+        {
+            get => NativeMethods.cpSpaceGetCollisionBias(space);
+            set => NativeMethods.cpSpaceSetCollisionBias(space, value);
+        }
+
+        /// <summary>
+        /// Number of frames that contact information should persist. Defaults to 3. There is
+        /// probably never a reason to change this value.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public int CollisionPersistence
+        {
+            get => (int)NativeMethods.cpSpaceGetCollisionPersistence(space);
+            set => NativeMethods.cpSpaceSetCollisionPersistence(space, (uint)value);
+        }
+
+        /// <summary>
+        /// The Space provided static body for a given <see cref="Space"/>.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public Body StaticBody
+        {
+            get
+            {
+                cpBody bodyHandle = NativeMethods.cpSpaceGetStaticBody(space);
+                cpDataPointer gcHandle = NativeMethods.cpBodyGetUserData(bodyHandle);
+
+                if (gcHandle != IntPtr.Zero)
+                {
+                    return NativeInterop.FromIntPtr<Body>(gcHandle);
+                }
+
+                return new Body(bodyHandle);
+            }
+        }
+
+        /// <summary>
+        /// 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.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public double CurrentTimeStep => NativeMethods.cpSpaceGetCurrentTimeStep(space);
+
+        /// <summary>
+        /// Returns true from inside a callback when objects cannot be added/removed.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public bool IsLocked => NativeMethods.cpSpaceIsLocked(space) != 0;
+
+
+        // Collision Handlers
+
+        /// <summary>
+        /// Create or return the existing collision handler that is called for all collisions that are
+        /// not handled by a more specific collision handler.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public CollisionHandler GetOrCreateDefaultCollisionHandler()
+        {
+            cpCollisionHandlerPointer collisionHandle = NativeMethods.cpSpaceAddDefaultCollisionHandler(space);
+            return CollisionHandler.GetOrCreate(collisionHandle);
+        }
+
+        /// <summary>
+        /// 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.
+        /// </summary>
+        [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);
+        }
+
+
+        /// <summary>
+        /// Create or return the existing wildcard collision handler for the specified type.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public CollisionHandler GetOrCreateWildcardHandler(int type)
+        {
+            cpCollisionHandlerPointer collisionHandle = NativeMethods.cpSpaceAddWildcardHandler(space, (cpCollisionType)type);
+            return CollisionHandler.GetOrCreate(collisionHandle);
+        }
+
+        /// <summary>
+        /// Add a collision shape to the simulation.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public void AddShape(Shape shape)
+        {
+            NativeMethods.cpSpaceAddShape(space, shape.Handle);
+        }
+
+        /// <summary>
+        /// Add a rigid body to the simulation.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public void AddBody(Body body)
+        {
+            NativeMethods.cpSpaceAddBody(space, body.Handle);
+        }
+
+        /// <summary>
+        /// Add a constraint to the simulation.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public void AddConstraint(Constraint constraint)
+        {
+            NativeMethods.cpSpaceAddConstraint(space, constraint.Handle);
+        }
+
+        /// <summary>
+        /// Remove a collision shape from the simulation.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public void RemoveShape(Shape shape)
+        {
+            NativeMethods.cpSpaceRemoveShape(space, shape.Handle);
+        }
+
+        /// <summary>
+        /// Remove a rigid body from the simulation.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public void RemoveBody(Body body)
+        {
+            NativeMethods.cpSpaceRemoveBody(space, body.Handle);
+        }
+
+        /// <summary>
+        /// Remove a constraint from the simulation.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public void RemoveConstraint(Constraint constraint)
+        {
+            NativeMethods.cpSpaceRemoveConstraint(space, constraint.Handle);
+        }
+
+        /// <summary>
+        /// Test if a collision shape has been added to the space.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public bool Contains(Shape shape)
+        {
+            return NativeMethods.cpSpaceContainsShape(space, shape.Handle) != 0;
+        }
+
+        /// <summary>
+        /// Test if a rigid body has been added to the space.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public bool Contains(Body body)
+        {
+            return NativeMethods.cpSpaceContainsBody(space, body.Handle) != 0;
+        }
+
+        /// <summary>
+        /// Test if a constraint has been added to the space.
+        /// </summary>
+        [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<object>(handleKey);
+            var data = NativeInterop.FromIntPtr<PostStepCallbackInfo>(handleData);
+
+            Action<Space, object, object> callback = data.Callback;
+
+            callback(space, key, data.Data);
+
+            NativeInterop.ReleaseHandle(handleKey);
+            NativeInterop.ReleaseHandle(handleData);
+        }
+
+        private static PostStepFunction postStepCallBack = PostStepCallBack;
+
+        /// <summary>
+        /// Schedule a post-step callback to be called when <see cref="Step"/> finishes. You can
+        /// only register one callback per unique value for <paramref name="key"/>. Returns true
+        /// only if <paramref name="key"/> has never been scheduled before. It's possible to pass
+        /// null for <paramref name="callback"/> if you only want to mark <paramref name="key"/> as
+        /// being used.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public bool AddPostStepCallback(Action<Space, object, object> 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<PointQueryInfo>)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;
+
+        /// <summary>
+        /// 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
+        /// <paramref name="maxDistance"/> is also allowed meaning that the point must be a under a
+        /// certain depth within a shape to be considered a match.
+        /// </summary>
+        /// <param name="point">Where to check for shapes in the space.</param>
+        /// <param name="maxDistance">Match only within this distance.</param>
+        /// <param name="filter">Only pick shapes matching the filter.</param>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public IReadOnlyList<PointQueryInfo> PointQuery(Vect point, double maxDistance, ShapeFilter filter)
+        {
+            var list = new List<PointQueryInfo>();
+            var gcHandle = GCHandle.Alloc(list);
+
+            NativeMethods.cpSpacePointQuery(space, point, maxDistance, filter, eachPointQuery.ToFunctionPointer(), GCHandle.ToIntPtr(gcHandle));
+
+            gcHandle.Free();
+            return list;
+        }
+
+        /// <summary>
+        /// 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
+        /// <paramref name="maxDistance"/> of 0.0 is used, the point must lie inside a shape.
+        /// Negative <paramref name="maxDistance"/> is also allowed, meaning that the point must be
+        /// under a certain depth within a shape to be considered a match.
+        /// </summary>
+        /// <param name="point">Where to check for collision in the space.</param>
+        /// <param name="maxDistance">Match only within this distance.</param>
+        /// <param name="filter">Only pick shapes matching the filter.</param>
+        [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<SegmentQueryInfo>)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;
+
+        /// <summary>
+        /// 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.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public IReadOnlyList<SegmentQueryInfo> SegmentQuery(Vect start, Vect end, double radius, ShapeFilter filter)
+        {
+            var list = new List<SegmentQueryInfo>();
+            var gcHandle = GCHandle.Alloc(list);
+
+            NativeMethods.cpSpaceSegmentQuery(space, start, end, radius, filter, eachSegmentQuery.ToFunctionPointer(), GCHandle.ToIntPtr(gcHandle));
+
+            gcHandle.Free();
+            return list;
+        }
+
+        /// <summary>
+        /// 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.
+        /// </summary>
+        [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<Shape>)GCHandle.FromIntPtr(data).Target;
+
+            var shape = Shape.FromHandle(shapeHandle);
+
+            list.Add(shape);
+        }
+
+        private static SpaceBBQueryFunction eachBBQuery = EachBBQuery;
+
+
+        /// <summary>
+        /// 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.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public IReadOnlyList<Shape> BoundBoxQuery(BoundingBox bb, ShapeFilter filter)
+        {
+            var list = new List<Shape>();
+
+            var gcHandle = GCHandle.Alloc(list);
+
+            NativeMethods.cpSpaceBBQuery(space, bb, filter, eachBBQuery.ToFunctionPointer(), GCHandle.ToIntPtr(gcHandle));
+
+            gcHandle.Free();
+            return list;
+        }
+
+        /// <summary>
+        /// Get all bodies in the space.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public IReadOnlyList<Body> Bodies
+        {
+            get
+            {
+                int count = NativeMethods.cpSpaceGetBodyCount(space);
+
+                if (count == 0)
+                    return Array.Empty<Body>();
+
+                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<Body>(userDataArray[i]);
+                    bodies[i] = b;
+                }
+
+                return bodies;
+            }
+        }
+
+        /// <summary>
+        /// Get dynamic bodies in the space.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public IReadOnlyList<Body> DynamicBodies
+        {
+            get
+            {
+                int count = NativeMethods.cpSpaceGetDynamicBodyCount(space);
+
+                if (count == 0)
+                    return Array.Empty<Body>();
+
+                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<Body>(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<Shape>)GCHandle.FromIntPtr(data).Target;
+
+            var shape = Shape.FromHandle(shapeHandle);
+
+            list.Add(shape);
+        }
+
+        private static SpaceObjectIteratorFunction eachShape = EachShape;
+
+        /// <summary>
+        /// Get all shapes in the space.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public IReadOnlyList<Shape> Shapes
+        {
+            get
+            {
+                var list = new List<Shape>();
+
+                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<ContactPointSet>)GCHandle.FromIntPtr(data).Target;
+
+            var pointSet = NativeInterop.PtrToStructure<cpContactPointSet>(pointsPointer);
+
+            list.Add(ContactPointSet.FromContactPointSet(pointSet));
+        }
+
+        private static SpaceShapeQueryFunction shapeQueryCallback = ShapeQueryCallback;
+
+        /// <summary>
+        /// Get all shapes in the space that are overlapping the given shape.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public IReadOnlyList<ContactPointSet> ShapeQuery(Shape shape)
+        {
+            var list = new List<ContactPointSet>();
+            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<Constraint>)GCHandle.FromIntPtr(data).Target;
+
+            var constraint = Constraint.FromHandle(constraintHandle);
+
+            list.Add(constraint);
+        }
+
+        private static SpaceObjectIteratorFunction eachConstraint = EachConstraint;
+
+
+        /// <summary>
+        /// Get all constraints in the space.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public IReadOnlyList<Constraint> Constraints
+        {
+            get
+            {
+                var list = new List<Constraint>();
+
+                var gcHandle = GCHandle.Alloc(list);
+
+                NativeMethods.cpSpaceEachConstraint(space, eachConstraint.ToFunctionPointer(), GCHandle.ToIntPtr(gcHandle));
+
+                gcHandle.Free();
+
+                return list;
+            }
+        }
+
+        /// <summary>
+        /// Update the collision detection info for the static shapes in the space.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public void ReindexStatic()
+        {
+            NativeMethods.cpSpaceReindexStatic(space);
+        }
+
+        /// <summary>
+        /// Update the collision detection data for a specific shape in the space.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public void ReindexShape(Shape shape)
+        {
+            NativeMethods.cpSpaceReindexShape(space, shape.Handle);
+        }
+
+        /// <summary>
+        /// Update the collision detection data for all shapes attached to a body.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public void ReindexShapesForBody(Body body)
+        {
+            NativeMethods.cpSpaceReindexShapesForBody(space, body.Handle);
+        }
+
+        /// <summary>
+        /// Switch the space to use a spatial hash as its spatial index.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public void UseSpatialHash(double dim, int count)
+        {
+            NativeMethods.cpSpaceUseSpatialHash(space, dim, count);
+        }
+
+        /// <summary>
+        /// 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.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public virtual void Step(double dt)
+        {
+            NativeMethods.cpSpaceStep(space, dt);
+        }
+
+        /// <summary>
+        /// Draw all objects in the space for debugging purposes.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public void DebugDraw(IDebugDraw debugDraw)
+        {
+            DebugDraw(debugDraw, DebugDrawFlags.All, DebugDrawColors.Default);
+        }
+
+        /// <summary>
+        /// Draw all objects in the space for debugging purposes using flags.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public void DebugDraw(IDebugDraw debugDraw, DebugDrawFlags flags)
+        {
+            DebugDraw(debugDraw, flags, DebugDrawColors.Default);
+        }
+
+        /// <summary>
+        /// Draw all objects in the space for debugging purposes using flags and colors.
+        /// </summary>
+        [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/wrapper/PhysicsActor.cs b/src/Tizen.NUI.Physics2D/src/public/wrapper/PhysicsActor.cs
new file mode 100644 (file)
index 0000000..2c2684b
--- /dev/null
@@ -0,0 +1,199 @@
+/*
+ * 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.InteropServices;
+using Tizen.NUI.BaseComponents;
+
+namespace Tizen.NUI.Physics2D
+{
+    /// <summary>
+    /// Class to associate a physics body (such as btRigidBody*) with a View
+    /// for rendering.
+    ///
+    /// This object offers methods to modify basic physics properties
+    /// asynchronously, that is, on the Update thread.
+    ///
+    /// Currently, using the Physics API directly should be done after
+    /// blocking the physics integration step, by getting a ScopedAccessor from
+    /// the PhysicsAdaptor. Once the ScopedAccessor is disposed, then the
+    /// physics integration will run again.
+    /// </summary>
+    [EditorBrowsable(EditorBrowsableState.Never)]
+    public class PhysicsActor : BaseHandle
+    {
+#pragma warning disable IDE0032
+        private readonly View _view;
+#pragma warning restore IDE0032
+
+        /// <summary>
+        /// View is the view used for rendering the associated physics body.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public NUI.BaseComponents.View View => _view;
+
+        /// <summary>
+        /// Binds the actor to the given body. This should be a body that has
+        /// been added to the physics world, and has physical postion and
+        /// rotation in that space. The Actor is used to render that object in
+        /// DALi space.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public PhysicsActor(View view, Chipmunk.Body body, PhysicsAdaptor adaptor)
+            : this(Interop.Actor.PhysicsActorNew(View.getCPtr(view), body.Handle, PhysicsAdaptor.getCPtr(adaptor)), true)
+        {
+            this._view = view;
+            if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
+        }
+
+        /// <summary>
+        /// Copy Constructor
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public PhysicsActor(PhysicsActor adaptor) : this( Interop.Actor.NewPhysicsActor(PhysicsActor.getCPtr(adaptor)), true)
+        {
+            if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
+        }
+
+        /// <summary>
+        /// Assignment "operator"
+        /// </summary>
+        internal PhysicsActor Assign(PhysicsActor rhs)
+        {
+            PhysicsActor adaptor = new PhysicsActor(Interop.Actor.Assign(SwigCPtr, PhysicsActor.getCPtr(rhs)), false);
+            if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
+            return adaptor;
+        }
+
+        internal PhysicsActor(global::System.IntPtr cPtr, bool cMemoryOwn) : base(cPtr, cMemoryOwn)
+        {
+        }
+
+        /// <summary>
+        /// Dispose the physics actor
+        /// This will release the View, but it's up to the caller to release the Body.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        protected override void Dispose(DisposeTypes type)
+        {
+            if(disposed)
+            {
+                return;
+            }
+            if(type == DisposeTypes.Explicit)
+            {
+                // Called by user
+                // Release managed resources
+            }
+            // Release unmanaged resources
+
+            base.Dispose(type);
+        }
+
+        /**
+         */
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        protected override void ReleaseSwigCPtr(global::System.Runtime.InteropServices.HandleRef swigCPtr)
+        {
+            Interop.Actor.DeletePhysicsActor(swigCPtr);
+        }
+
+        /// <summary>
+        /// Get the physics body associated with this physics actor
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public Chipmunk.Body GetBody()
+        {
+            IntPtr cPtr = Interop.Actor.GetBody(SwigCPtr);
+            if(NDalicPINVOKE.SWIGPendingException.Pending)
+                throw NDalicPINVOKE.SWIGPendingException.Retrieve();
+            return new Chipmunk.Body(cPtr);
+        }
+
+        /// <summary>
+        /// Queue a method to set the position on the associated physics body
+        /// in the update thread before the next integration.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public void AsyncSetPhysicsPosition(Vector3 position)
+        {
+            Interop.Actor.AsyncSetPhysicsPosition(SwigCPtr, Vector3.getCPtr(position));
+            if(NDalicPINVOKE.SWIGPendingException.Pending)
+                throw NDalicPINVOKE.SWIGPendingException.Retrieve();
+        }
+
+        /// <summary>
+        /// Queue a method to set the rotation of the associated physics body
+        /// in the update thread before the next integration.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public void AsyncSetPhysicsRotation(Rotation position)
+        {
+            Interop.Actor.AsyncSetPhysicsRotation(SwigCPtr, Rotation.getCPtr(position));
+            if(NDalicPINVOKE.SWIGPendingException.Pending)
+                throw NDalicPINVOKE.SWIGPendingException.Retrieve();
+        }
+
+        /// <summary>
+        /// Get the current position of the physics body in Physics space.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public Vector3 GetPhysicsPosition()
+        {
+            IntPtr cPtr = Interop.Actor.GetPhysicsPosition(SwigCPtr);
+            if(NDalicPINVOKE.SWIGPendingException.Pending)
+                throw NDalicPINVOKE.SWIGPendingException.Retrieve();
+            return new Vector3(cPtr, true);
+        }
+
+        /// <summary>
+        /// Get the current rotation of the physics body in Physics space.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public Rotation GetPhysicsRotation()
+        {
+            IntPtr cPtr = Interop.Actor.GetPhysicsRotation(SwigCPtr);
+            if(NDalicPINVOKE.SWIGPendingException.Pending)
+                throw NDalicPINVOKE.SWIGPendingException.Retrieve();
+            return new Rotation(cPtr, true);
+        }
+
+        /// <summary>
+        /// Get the current position of the View in world space
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public Vector3 GetActorPosition()
+        {
+            IntPtr cPtr = Interop.Actor.GetActorPosition(SwigCPtr);
+            if(NDalicPINVOKE.SWIGPendingException.Pending)
+                throw NDalicPINVOKE.SWIGPendingException.Retrieve();
+            return new Vector3(cPtr, true);
+        }
+
+        /// <summary>
+        /// Get the current rotation of the View in world space
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public Rotation GetActorRotation()
+        {
+            IntPtr cPtr = Interop.Actor.GetActorRotation(SwigCPtr);
+            if(NDalicPINVOKE.SWIGPendingException.Pending)
+                throw NDalicPINVOKE.SWIGPendingException.Retrieve();
+            return new Rotation(cPtr, true);
+        }
+    }
+}
diff --git a/src/Tizen.NUI.Physics2D/src/public/wrapper/PhysicsAdaptor.cs b/src/Tizen.NUI.Physics2D/src/public/wrapper/PhysicsAdaptor.cs
new file mode 100644 (file)
index 0000000..3dd72f2
--- /dev/null
@@ -0,0 +1,439 @@
+/*
+ * 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.ComponentModel;
+using System.Runtime.InteropServices;
+using Tizen.NUI.BaseComponents;
+using Tizen.NUI.Binding;
+using Tizen.NUI;
+
+namespace Tizen.NUI.Physics2D
+{
+    /// <summary>
+    /// Enumeration to turn the integration step on or off.
+    /// </summary>
+    [EditorBrowsable(EditorBrowsableState.Never)]
+    public enum IntegrationState
+        {
+            ///<summary>
+            ///Integration state is turned off - physics stops running
+            ///</summary>
+            Off,
+
+            ///<summary>
+            ///Integration state is turned on - physics runs in Update thread
+            ///</summary>
+            On
+        };
+
+    /// <summary>
+    /// Enumeration to turn the debug layer on or off.
+    /// </summary>
+    [EditorBrowsable(EditorBrowsableState.Never)]
+    public enum DebugState
+        {
+            ///<summary>
+            ///Debug state is turned off - no debug is drawn
+            ///</summary>
+            Off,
+
+            ///<summary>
+            ///Debug state is turned on - if there is a Debug layer, then
+            ///the physics debug is drawn over the top of the root layer
+            ///</summary>
+            On
+        };
+
+    /// <summary>
+    /// Adaptor to manage access to the physics world and pairing actors and physics
+    /// bodies, plus some translation methods to/from the physics space and dali space.
+    ///
+    /// Also manages a debug renderer that may utilize the physics engine debug.
+    /// It is up to the developer to retrieve the root actor and parent it into the scene.
+    ///
+    /// </summary>
+    [EditorBrowsable(EditorBrowsableState.Never)]
+    public class PhysicsAdaptor : NUI.BaseHandle
+    {
+        /// <summary>
+        /// Initialize the physics system.
+        /// <param name="transform"> Transformation matrix from NUI space to the Physics Space</param>
+        /// <param name="size">Size of the root layer that the adaptor creates</param>
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public PhysicsAdaptor(NUI.Matrix transform, NUI.Vector2 size)
+            : this(Interop.Adaptor.PhysicsAdaptorNew(NUI.Matrix.getCPtr(transform), NUI.Vector2.getCPtr(size)), true)
+        {
+            if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
+        }
+
+        /// <summary>
+        /// Copy Constructor
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public PhysicsAdaptor(PhysicsAdaptor adaptor) : this( Interop.Adaptor.NewPhysicsAdaptor(PhysicsAdaptor.getCPtr(adaptor)), true)
+        {
+            if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
+        }
+
+        internal PhysicsAdaptor Assign(PhysicsAdaptor rhs)
+        {
+            PhysicsAdaptor adaptor = new PhysicsAdaptor(Interop.Adaptor.Assign(SwigCPtr, PhysicsAdaptor.getCPtr(rhs)), false);
+            if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
+            return adaptor;
+        }
+
+        internal PhysicsAdaptor(global::System.IntPtr cPtr, bool cMemoryOwn) : base(cPtr, cMemoryOwn)
+        {
+        }
+
+        /// <summary>
+        /// Dispose the PhysicsAdaptor
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        protected override void Dispose(DisposeTypes type)
+        {
+            if(disposed)
+            {
+                return;
+            }
+            if(type == DisposeTypes.Explicit)
+            {
+                // Called by user
+                // Release managed resources
+            }
+            // Release unmanaged resources
+
+            base.Dispose(type);
+        }
+
+        /// This will not be publicly opened
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        protected override void ReleaseSwigCPtr(global::System.Runtime.InteropServices.HandleRef swigCPtr)
+        {
+            Interop.Adaptor.DeletePhysicsAdaptor(swigCPtr);
+        }
+
+        /// <summary>
+        /// The time that the integration step notionally takes.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public float Timestep
+        {
+            get
+            {
+                return GetTimestep();
+            }
+            set
+            {
+                SetTimestep(value);
+            }
+        }
+
+        internal float GetTimestep()
+        {
+            float timestep = Interop.Adaptor.GetTimestep(SwigCPtr);
+            if(NDalicPINVOKE.SWIGPendingException.Pending)
+                throw NDalicPINVOKE.SWIGPendingException.Retrieve();
+            return timestep;
+        }
+        internal void SetTimestep(float timestep)
+        {
+            Interop.Adaptor.SetTimestep(SwigCPtr, timestep);
+            if(NDalicPINVOKE.SWIGPendingException.Pending)
+                throw NDalicPINVOKE.SWIGPendingException.Retrieve();
+        }
+
+        /// <summary>
+        /// Property to handle the IntegrationState of the adaptor
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public IntegrationState IntegrationState
+        {
+            get
+            {
+                return GetIntegrationState();
+            }
+            set
+            {
+                SetIntegrationState(value);
+            }
+        }
+        internal IntegrationState GetIntegrationState()
+        {
+            int state = Interop.Adaptor.GetIntegrationState(SwigCPtr);
+            if(NDalicPINVOKE.SWIGPendingException.Pending)
+                throw NDalicPINVOKE.SWIGPendingException.Retrieve();
+            return (IntegrationState)state;
+        }
+        internal void SetIntegrationState(IntegrationState state)
+        {
+            Interop.Adaptor.SetIntegrationState(SwigCPtr, (int)state);
+            if(NDalicPINVOKE.SWIGPendingException.Pending)
+                throw NDalicPINVOKE.SWIGPendingException.Retrieve();
+        }
+
+        /// <summary>
+        /// Property to handle the debug state of the adaptor
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public Physics2D.DebugState DebugState
+        {
+            get
+            {
+                return GetDebugState();
+            }
+            set
+            {
+                SetDebugState(value);
+            }
+        }
+        internal DebugState GetDebugState()
+        {
+            int state = Interop.Adaptor.GetDebugState(SwigCPtr);
+            if(NDalicPINVOKE.SWIGPendingException.Pending)
+                throw NDalicPINVOKE.SWIGPendingException.Retrieve();
+            return (DebugState)state;
+        }
+        internal void SetDebugState(DebugState state)
+        {
+            Interop.Adaptor.SetDebugState(SwigCPtr, (int)state);
+            if(NDalicPINVOKE.SWIGPendingException.Pending)
+                throw NDalicPINVOKE.SWIGPendingException.Retrieve();
+        }
+
+
+        /// <summary>
+        /// Change the transform matrix or the size of the root view
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public void SetTransformAndSize(Matrix transform, Vector2 size)
+        {
+            Interop.Adaptor.SetTransformAndSize(SwigCPtr, Matrix.getCPtr(transform), Vector2.getCPtr(size));
+            if(NDalicPINVOKE.SWIGPendingException.Pending)
+                throw NDalicPINVOKE.SWIGPendingException.Retrieve();
+        }
+
+        /// <summary>
+        /// Return an accessor to the physics world.
+        /// Internally, this locks a mutex to prevent the integration step from running,
+        /// this will also block the Update thread. It is important that this accessor
+        /// is disposed of when not needed to restart the update thread. (Suggest use of
+        /// "using" block).
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public ScopedPhysicsAccessor GetAccessor()
+        {
+            global::System.IntPtr worldCPtr = Interop.Adaptor.GetPhysicsWorld(SwigCPtr);
+            if(NDalicPINVOKE.SWIGPendingException.Pending)
+                throw NDalicPINVOKE.SWIGPendingException.Retrieve();
+            return new ScopedPhysicsAccessor(worldCPtr);
+        }
+
+        /// <summary>
+        /// Add a view to the body. The view will be used to render the body. It is parented onto the root layer.
+        /// The physics body should be added to the physics space by the user.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public PhysicsActor AddViewToBody(View view, Chipmunk.Body body)
+        {
+            // @todo Converting a View to an Actor internally _should_ be OK?!
+            global::System.IntPtr cPtr = Interop.Adaptor.AddActorBody(SwigCPtr, View.getCPtr(view), body.Handle);
+            if(NDalicPINVOKE.SWIGPendingException.Pending)
+                throw NDalicPINVOKE.SWIGPendingException.Retrieve();
+            return new PhysicsActor(cPtr, false);
+        }
+
+        /// <summary>
+        /// This will unparent the View from the root layer, and dis-associate it
+        /// from the physics body. It is the responsibility of the user to remove
+        /// the physics body from the world.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public void RemoveViewFromBody(PhysicsActor actor)
+        {
+            Interop.Adaptor.RemoveActorBody(SwigCPtr, PhysicsActor.getCPtr(actor));
+            if(NDalicPINVOKE.SWIGPendingException.Pending)
+                throw NDalicPINVOKE.SWIGPendingException.Retrieve();
+        }
+
+        /// <summary>
+        /// Retrieve a PhysicsActor given a physics body.
+        /// If there is no associated PhysicsActor, this will return null.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public PhysicsActor GetPhysicsActor(Chipmunk.Body body)
+        {
+            global::System.IntPtr cPtr = Interop.Adaptor.GetPhysicsActor(SwigCPtr, body.Handle);
+            if(NDalicPINVOKE.SWIGPendingException.Pending)
+                throw NDalicPINVOKE.SWIGPendingException.Retrieve();
+
+            // @todo This creates a new PhysicsActor on native side, but it's
+            // not registered with native or c# registries. Do we need to add functionality?
+            if(cPtr != global::System.IntPtr.Zero)
+            {
+                return new PhysicsActor(cPtr, false);
+            }
+            else
+            {
+                return null;
+            }
+        }
+
+        /// <summary>
+        ///
+        /// </summary>
+        //public Layer GetRootLayer()... it's needed for 2 things - touch and finding actors.
+        // Provide a PhysisActor api to get View back
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public Layer GetRootLayer()
+        {
+            global::System.IntPtr cPtr = Interop.Adaptor.GetRootActor(SwigCPtr);
+            if(NDalicPINVOKE.SWIGPendingException.Pending)
+                throw NDalicPINVOKE.SWIGPendingException.Retrieve();
+
+            // @todo Test against registry?
+            Layer layer = new Layer(cPtr, false);
+            if(NDalicPINVOKE.SWIGPendingException.Pending)
+                throw NDalicPINVOKE.SWIGPendingException.Retrieve();
+            return layer;
+        }
+
+        /// <summary>
+        /// Convert a touch point into a picking ray in the Physics space.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public void BuildPickingRay(Vector3 origin, Vector3 direction, /*out*/ Vector3 rayFromWorld, /*out*/ Vector3 rayToWorld)
+        {
+            Interop.Adaptor.BuildPickingRay(SwigCPtr, Vector3.getCPtr(origin), Vector3.getCPtr(direction),
+                                            Vector3.getCPtr(rayFromWorld), Vector3.getCPtr(rayToWorld));
+            if(NDalicPINVOKE.SWIGPendingException.Pending)
+                throw NDalicPINVOKE.SWIGPendingException.Retrieve();
+        }
+
+        /// <summary>
+        /// Project a point from the origin (in NUI space) a distance along the direction
+        /// vector (in NUI space) and returns the projected point in physics space.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public Vector3 ProjectPoint(Vector3 origin, Vector3 direction, float distance)
+        {
+            global::System.IntPtr cPtr = Interop.Adaptor.ProjectPoint(SwigCPtr, Vector3.getCPtr(origin), Vector3.getCPtr(direction), distance);
+            if(NDalicPINVOKE.SWIGPendingException.Pending)
+                throw NDalicPINVOKE.SWIGPendingException.Retrieve();
+            return new Vector3(cPtr, true);
+        }
+
+        /// <summary>
+        /// Transforms a position from NUI space to physics space
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public Vector3 TransformPositionToPhysicsSpace(Vector3 position)
+        {
+            global::System.IntPtr cPtr = Interop.Adaptor.TranslatePositionToPhysicsSpace(SwigCPtr, Vector3.getCPtr(position));
+            if(NDalicPINVOKE.SWIGPendingException.Pending)
+                throw NDalicPINVOKE.SWIGPendingException.Retrieve();
+            return new Vector3(cPtr, true);
+        }
+
+        /// <summary>
+        /// Transform a rotation from NUI to physics space
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public Rotation TransformRotationToPhysicsSpace(Rotation rotation)
+        {
+            global::System.IntPtr cPtr = Interop.Adaptor.TranslateRotationToPhysicsSpace(SwigCPtr, Rotation.getCPtr(rotation));
+            if(NDalicPINVOKE.SWIGPendingException.Pending)
+                throw NDalicPINVOKE.SWIGPendingException.Retrieve();
+            return new Rotation(cPtr, true);
+        }
+
+        /// <summary>
+        /// Transform a position in Physics space to NUI space
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public Vector3 TransformPositionFromPhysicsSpace(Vector3 position)
+        {
+            global::System.IntPtr cPtr = Interop.Adaptor.TranslatePositionFromPhysicsSpace(SwigCPtr, Vector3.getCPtr(position));
+            if(NDalicPINVOKE.SWIGPendingException.Pending)
+                throw NDalicPINVOKE.SWIGPendingException.Retrieve();
+            return new Vector3(cPtr, true);
+        }
+
+        /// <summary>
+        /// Convert a rotation in physics space into NUI space
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public Rotation TransformRotationFromPhysicsSpace(Rotation rotation)
+        {
+            global::System.IntPtr cPtr = Interop.Adaptor.TranslateRotationFromPhysicsSpace(SwigCPtr, Rotation.getCPtr(rotation));
+            if(NDalicPINVOKE.SWIGPendingException.Pending)
+                throw NDalicPINVOKE.SWIGPendingException.Retrieve();
+            return new Rotation(cPtr, true);
+        }
+
+        /// <summary>
+        /// Converts a vector (not a point) in NUI space to Physics space
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public Vector3 ConvertVectorToPhysicsSpace(Vector3 vector)
+        {
+            global::System.IntPtr cPtr = Interop.Adaptor.ConvertVectorToPhysicsSpace(SwigCPtr, Vector3.getCPtr(vector));
+            if(NDalicPINVOKE.SWIGPendingException.Pending)
+                throw NDalicPINVOKE.SWIGPendingException.Retrieve();
+            return new Vector3(cPtr, true);
+        }
+
+        /// <summary>
+        /// Converts a vector (not a point) in physics space to NUI space.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public Vector3 ConvertVectorFromPhysicsSpace(Vector3 vector)
+        {
+            global::System.IntPtr cPtr = Interop.Adaptor.ConvertVectorFromPhysicsSpace(SwigCPtr, Vector3.getCPtr(vector));
+            if(NDalicPINVOKE.SWIGPendingException.Pending)
+                throw NDalicPINVOKE.SWIGPendingException.Retrieve();
+            return new Vector3(cPtr, true);
+        }
+
+        /// <summary>
+        /// The debug layer uses a drawable actor and the debug features of the native physics engine
+        /// to render any debug graphics for the physics bodies.
+        /// This layer needs to be created before setting the DebugState has any effect.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public Layer CreateDebugLayer(Window window)
+        {
+            global::System.IntPtr cPtr = Interop.Adaptor.CreateDebugLayer(SwigCPtr, Window.getCPtr(window));
+            if(NDalicPINVOKE.SWIGPendingException.Pending)
+                throw NDalicPINVOKE.SWIGPendingException.Retrieve();
+            return new Layer(cPtr, false);
+        }
+
+        /// <summary>
+        /// A sync point is necessary to synchronize Async calls in the update thread.
+        /// Any use of the PhysicsActor.AsyncNNN calls will require this API to be called.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public void CreateSyncPoint()
+        {
+            Interop.Adaptor.CreateSyncPoint(SwigCPtr);
+            if(NDalicPINVOKE.SWIGPendingException.Pending)
+                throw NDalicPINVOKE.SWIGPendingException.Retrieve();
+        }
+
+        // @todo Define interface for Queue that can accept cdecls.
+    }
+}
diff --git a/src/Tizen.NUI.Physics2D/src/public/wrapper/ScopedPhysicsAccessor.cs b/src/Tizen.NUI.Physics2D/src/public/wrapper/ScopedPhysicsAccessor.cs
new file mode 100644 (file)
index 0000000..2af0dc3
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ * 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.InteropServices;
+using System.Collections.Generic;
+
+using Tizen.NUI;
+using Tizen.NUI.BaseComponents;
+
+namespace Tizen.NUI.Physics2D
+{
+    /// <summary>
+    /// Scoped accessor to the physics world.
+    ///
+    /// Automatically locks the physics world with a mutex to prevent the
+    /// integration step from running whilst the developer is accessing
+    /// the world, e.g. to add/remove bodies or constraints, or to
+    /// perform hit-test.
+    ///
+    /// When it is disposed, the mutex is unlocked, and the integration step
+    /// can resume.
+    ///
+    /// Suggest that this is created with a "using" block:
+    ///
+    /// using(accessor=physicsAdaptor.GetAccessor())
+    /// {
+    ///   var space = accessor.GetNative();
+    ///   // Perform operations on space or bodies.
+    /// } // automatically disposed.
+    /// </summary>
+    [EditorBrowsable(EditorBrowsableState.Never)]
+    public class ScopedPhysicsAccessor : IDisposable
+    {
+        private IntPtr worldCPtr;
+
+        // Can only be constructed by PhysicsAdaptor
+        internal ScopedPhysicsAccessor(IntPtr worldCPtr)
+        {
+            this.worldCPtr = worldCPtr;
+            Interop.World.Lock(worldCPtr);
+            if(NDalicPINVOKE.SWIGPendingException.Pending)
+                throw NDalicPINVOKE.SWIGPendingException.Retrieve();
+        }
+
+        /// <summary>
+        /// Get a weak handle to the native physics space. Disposing of
+        /// this handle does not destroy the space.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public Chipmunk.SpaceRef GetNative()
+        {
+            IntPtr spaceCPtr = Interop.World.GetNative(worldCPtr);
+            if(NDalicPINVOKE.SWIGPendingException.Pending)
+                throw NDalicPINVOKE.SWIGPendingException.Retrieve();
+            return new Chipmunk.SpaceRef(spaceCPtr);
+        }
+
+        /// <summary>
+        /// Perform a hit test on the given physics world ray, with a possible filter.
+        /// The ray can be created with PhysicsAdaptor.BuildPickingRay().
+        /// Returns a body if hit, along with the local pivot coordinates and the distance from the ray origin (usually camera)
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public Chipmunk.Body HitTest( NUI.Vector3 rayFromWorld, NUI.Vector3 rayToWorld, Chipmunk.ShapeFilter filter, /*out*/ NUI.Vector3 localPivot, out float distanceFromCamera)
+        {
+            IntPtr cPtr = Interop.World.HitTest(worldCPtr, NUI.Vector3.getCPtr(rayFromWorld), NUI.Vector3.getCPtr(rayToWorld), filter, NUI.Vector3.getCPtr(localPivot), out distanceFromCamera);
+            if(NDalicPINVOKE.SWIGPendingException.Pending)
+                throw NDalicPINVOKE.SWIGPendingException.Retrieve();
+            if(cPtr != global::System.IntPtr.Zero)
+            {
+                return new Chipmunk.Body(cPtr);
+            }
+            return null;
+        }
+
+        /// <summary>
+        /// Dispose of this object.
+        /// This ensures that the integration step is resumed
+        /// </summary>
+        protected virtual void Dispose(bool disposing)
+        {
+            Interop.World.Unlock(worldCPtr);
+            if(NDalicPINVOKE.SWIGPendingException.Pending)
+                throw NDalicPINVOKE.SWIGPendingException.Retrieve();
+        }
+
+        /// <summary>
+        /// Disposes the Space object.
+        /// </summary>
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public void Dispose()
+        {
+            Dispose(true);
+            GC.SuppressFinalize(this);
+        }
+
+    }
+
+}
index e53710f..54301f4 100755 (executable)
@@ -27,6 +27,7 @@ using System.Runtime.CompilerServices;
 [assembly: InternalsVisibleTo("Tizen.NUI.Components, " + Tizen.NUI.PublicKey.TizenFX)]
 [assembly: InternalsVisibleTo("Tizen.NUI.Extension, " + Tizen.NUI.PublicKey.TizenFX)]
 [assembly: InternalsVisibleTo("Tizen.NUI.Scene3D, " + Tizen.NUI.PublicKey.TizenFX)]
+[assembly: InternalsVisibleTo("Tizen.NUI.Physics2D, " + Tizen.NUI.PublicKey.TizenFX)]
 
 [assembly: InternalsVisibleTo("Tizen.TV.NUI, " + Tizen.NUI.PublicKey.TizenTV)]
 [assembly: InternalsVisibleTo("Tizen.TV.NUI.Component, " + Tizen.NUI.PublicKey.TizenTV)]
index e790dec..93b6b70 100644 (file)
@@ -20,190 +20,112 @@ using System.Runtime.InteropServices;
 using System.Runtime.CompilerServices;
 using System.Text;
 using System.Linq;
+using Tizen.NUI;
+using Tizen.NUI.BaseComponents;
+using Tizen.NUI.Constants;
+using Tizen.NUI.Physics2D;
 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
+class Physics2DSample : NUIApplication
 {
-    public Physics2DSample()
+    static string IMAGE_DIR = Tizen.Applications.Application.Current.DirectoryInfo.Resource + "images/";
+
+    Window mWindow;
+    Vector2 mWindowSize;
+    Matrix mTransform;
+    PhysicsAdaptor mPhysicsAdaptor;
+
+    protected override void OnCreate()
     {
+        // Up call to the Base class first
+        base.OnCreate();
+
+        mWindow = Window.Instance;
+        mWindow.BackgroundColor = Color.DarkOrchid;
+        mWindowSize = mWindow.WindowSize;
+
+        mTransform = new Matrix();
+        mTransform.SetIdentityAndScale(new Vector3(1.0f, -1.0f, 1.0f));
+        mTransform.SetTranslation(new Vector3(mWindowSize.Width * 0.5f, mWindowSize.Height * 0.5f, 0.0f));
+
         // 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 + ")");
-        }
+        mPhysicsAdaptor = new PhysicsAdaptor(mTransform, mWindowSize);
+        mWindow.AddLayer(mPhysicsAdaptor.GetRootLayer());
 
-        // Make a point query on a shape
+        using (var accessor = mPhysicsAdaptor.GetAccessor())
         {
-            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
+            var space = accessor.GetNative();
+
+            // 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.0f, 0.0f); // Start point of the ground
+            var groundEnd = new Vect(1000.0f, 0.0f); // 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 = 13.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);
+
+            View ball;
+            ball = new ImageView(IMAGE_DIR + "blocks-ball.png")
             {
-                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();
+                Name = "ball",
+                Size = new Size(26, 26)
+            };
+
+            var physicsBall = mPhysicsAdaptor.AddViewToBody(ball, circleBody);
+            physicsBall.AsyncSetPhysicsPosition(new Vector3(0.0f, 100.0f, 0.0f));
+            // Auto dispose of accessor
         }
-        
-        // Clean up
-        groundShape1.Dispose();
-        groundShape2.Dispose();
-        circleShape.Dispose();
-    
-        groundBody1.Dispose();
-        groundBody2.Dispose();
-        circleBody.Dispose();
-    
-        space.Dispose();
+        mPhysicsAdaptor.CreateSyncPoint();
     }
-    
+
     /// <summary>
     /// The main entry point for the application.
     /// </summary>
@@ -211,6 +133,6 @@ class Physics2DSample
     static void Main(string[] args)
     {
         Physics2DSample example = new Physics2DSample();
+        example.Run(args);
     }
 }
-
diff --git a/test/Tizen.NUI.Physics2D.Sample/res/images/blocks-ball.png b/test/Tizen.NUI.Physics2D.Sample/res/images/blocks-ball.png
new file mode 100644 (file)
index 0000000..81e97d6
Binary files /dev/null and b/test/Tizen.NUI.Physics2D.Sample/res/images/blocks-ball.png differ