</ItemGroup>
<ItemGroup>
- <Folder Include="chipmunk\" />
+ <Folder Include="chipmunk" />
+ <Folder Include="interop" />
+ <Folder Include="wrapper" />
</ItemGroup>
</Project>
--- /dev/null
+/*
+ * 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);
+ }
+ }
+}
--- /dev/null
+/*
+ * 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);
+ }
+ }
+}
--- /dev/null
+/*
+ * 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
+ }
+ }
+}
--- /dev/null
+/*
+ * 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);
+ }
+ }
+}
* 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
/// <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
/// <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
* 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
RegisterUserData();
}
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ internal static Space NativeSpace(cpSpace handle)
+ {
+ return new Space(handle);
+ }
+
/// <summary>
/// Destroys and frees.
/// </summary>
}
/// <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
/// <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
/// <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
/// 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
}
/// <summary>
- /// Add a rigid body to the simulation.
+ /// Add a rigid body to the simulation.
/// </summary>
[EditorBrowsable(EditorBrowsableState.Never)]
public void AddBody(Body body)
--- /dev/null
+/*
+ * 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);
+ }
+
+ }
+}
--- /dev/null
+/*
+ * 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);
+ }
+ }
+}
--- /dev/null
+/*
+ * 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.
+ }
+}
--- /dev/null
+/*
+ * 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);
+ }
+
+ }
+
+}
[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)]
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>
static void Main(string[] args)
{
Physics2DSample example = new Physics2DSample();
+ example.Run(args);
}
}
-