Added integration api to physics 20/298620/6
authorDavid Steele <david.steele@samsung.com>
Mon, 11 Sep 2023 17:37:30 +0000 (18:37 +0100)
committerRichard Huang <r.huang@samsung.com>
Thu, 14 Sep 2023 12:57:14 +0000 (12:57 +0000)
Changed locking mechanism to enable NUI ScopedAccessor

Added 2nd user data to cpBody (for our ref, as c#
ref uses 1st user data)

Change-Id: Idf3ef1a172a03cbdbf587ef8993c787e1fa7c633

22 files changed:
automated-tests/src/dali-physics2d/CMakeLists.txt
automated-tests/src/dali-physics2d/utc-Dali-IntegPhysics.cpp [new file with mode: 0644]
build/tizen/dali-physics/CMakeLists.txt
dali-physics/integration-api/file.list [new file with mode: 0644]
dali-physics/integration-api/integ-physics-adaptor.cpp [new file with mode: 0644]
dali-physics/integration-api/integ-physics-adaptor.h [new file with mode: 0644]
dali-physics/integration-api/physics-world.cpp [new file with mode: 0644]
dali-physics/integration-api/physics-world.h [new file with mode: 0644]
dali-physics/internal/bullet-impl/bullet-physics-world-impl.cpp
dali-physics/internal/chipmunk-impl/chipmunk-physics-actor-impl.cpp
dali-physics/internal/chipmunk-impl/chipmunk-physics-adaptor-impl.cpp
dali-physics/internal/chipmunk-impl/chipmunk-physics-world-impl.cpp
dali-physics/internal/physics-adaptor-impl.cpp
dali-physics/internal/physics-adaptor-impl.h
dali-physics/internal/physics-world-impl.cpp
dali-physics/internal/physics-world-impl.h
dali-physics/public-api/scoped-physics-accessor.cpp
dali-physics/third-party/chipmunk2d/include/chipmunk/chipmunk_structs.h
dali-physics/third-party/chipmunk2d/include/chipmunk/cpBody.h
dali-physics/third-party/chipmunk2d/src/CMakeLists.txt
dali-physics/third-party/chipmunk2d/src/cpBody.c
packaging/dali-toolkit.spec

index ea0f140..e796089 100644 (file)
@@ -7,6 +7,7 @@ SET(RPM_NAME "core-${PKG_NAME}-tests")
 SET(TC_SOURCES
   utc-Dali-PhysicsAdaptor.cpp
   utc-Dali-PhysicsActor.cpp
+  utc-Dali-IntegPhysics.cpp
   )
 
 # List of test harness files (Won't get parsed for test cases)
diff --git a/automated-tests/src/dali-physics2d/utc-Dali-IntegPhysics.cpp b/automated-tests/src/dali-physics2d/utc-Dali-IntegPhysics.cpp
new file mode 100644 (file)
index 0000000..c79c495
--- /dev/null
@@ -0,0 +1,239 @@
+/*
+ * 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.
+ */
+
+#include <stdlib.h>
+#include <iostream>
+#include <typeinfo>
+
+// Need to override adaptor classes for toolkit test harness, so include
+// test harness headers before dali headers.
+#include <dali-physics/dali-physics.h>
+
+#include <dali-physics/integration-api/integ-physics-adaptor.h>
+#include <dali-physics/integration-api/physics-world.h>
+
+#include <dali-toolkit-test-suite-utils.h>
+#include <toolkit-event-thread-callback.h>
+
+#include <dali-toolkit/devel-api/controls/alignment/alignment.h>
+#include <dali-toolkit/public-api/controls/image-view/image-view.h>
+#include <dali/devel-api/adaptor-framework/window-devel.h>
+#include <dali/devel-api/events/hit-test-algorithm.h>
+
+#include <chipmunk/chipmunk.h>
+
+using namespace Dali;
+using namespace Dali::Toolkit::Physics;
+
+static const char* BALL_IMAGE = TEST_RESOURCE_DIR "/gallery-small-1.jpg";
+
+static cpBody* CreateBody(cpSpace* space)
+{
+  const float BALL_MASS       = 10.0f;
+  const float BALL_RADIUS     = 26.0f;
+  const float BALL_ELASTICITY = 0.5f;
+  const float BALL_FRICTION   = 0.5f;
+
+  cpBody* body = cpSpaceAddBody(space, cpBodyNew(BALL_MASS, cpMomentForCircle(BALL_MASS, 0.0f, BALL_RADIUS, cpvzero)));
+
+  cpShape* shape = cpSpaceAddShape(space, cpCircleShapeNew(body, BALL_RADIUS, cpvzero));
+  cpShapeSetElasticity(shape, BALL_ELASTICITY);
+  cpShapeSetFriction(shape, BALL_FRICTION);
+
+  return body;
+}
+
+// Defines a PolyShape
+static cpBody* CreateHexBody(cpSpace* space)
+{
+  const float MASS       = 10.0f;
+  const float RADIUS     = 26.0f;
+  const float ELASTICITY = 0.5f;
+  const float FRICTION   = 0.5f;
+
+  cpVect hexagon[6];
+  for(int i = 0; i < 6; i++)
+  {
+    cpFloat angle = -CP_PI * 2.0f * i / 6.0f;
+    hexagon[i]    = cpvmult(cpv(cos(angle), sin(angle)), RADIUS - 1.0f);
+  }
+
+  cpBody*  body  = cpSpaceAddBody(space, cpBodyNew(MASS, cpMomentForPoly(MASS, 6, hexagon, cpvzero, 0.0f)));
+  cpShape* shape = cpSpaceAddShape(space, cpPolyShapeNew(body, 6, hexagon, cpTransformIdentity, 1.0f));
+
+  cpShapeSetElasticity(shape, ELASTICITY);
+  cpShapeSetFriction(shape, FRICTION);
+
+  return body;
+}
+
+int UtcDaliPhysics2DIntegrationGetPhysicsWorld(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline("Testing getting the physics world");
+
+  Matrix         transform(true);
+  Uint16Pair     size(640, 480);
+  PhysicsAdaptor adaptor = PhysicsAdaptor::New(transform, size);
+  DALI_TEST_CHECK(adaptor);
+
+  Dali::Toolkit::Physics::Integration::PhysicsWorld world = Dali::Toolkit::Physics::Integration::GetPhysicsWorld(adaptor);
+
+  DALI_TEST_CHECK(world.GetImpl() != nullptr);
+
+  END_TEST;
+}
+
+int UtcDaliPhysics2DIntegrationPhysicsWorldLockUnlock(void)
+{
+  ToolkitTestApplication application;
+
+  Matrix         transform(true);
+  Uint16Pair     size(640, 480);
+  PhysicsAdaptor adaptor   = PhysicsAdaptor::New(transform, size);
+  Actor          rootActor = adaptor.GetRootActor();
+  auto           scene     = application.GetScene();
+  scene.Add(rootActor);
+
+  Dali::Actor ballActor = Toolkit::ImageView::New(BALL_IMAGE);
+
+  cpBody*      body{nullptr};
+  PhysicsActor physicsActor;
+  {
+    auto accessor = adaptor.GetPhysicsAccessor();
+    auto space    = accessor->GetNative().Get<cpSpace*>();
+    body          = CreateBody(space);
+    physicsActor  = adaptor.AddActorBody(ballActor, body);
+  }
+
+  DALI_TEST_CHECK(adaptor);
+  Dali::Toolkit::Physics::Integration::PhysicsWorld world = Dali::Toolkit::Physics::Integration::GetPhysicsWorld(adaptor);
+
+  world.Lock();
+  world.Unlock();
+
+  {
+    tet_infoline("Test that creating accessor after unlocking this does not lock up!");
+    auto accessor = adaptor.GetPhysicsAccessor();
+  }
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
+
+int UtcDaliPhysics2DIntegrationPhysicsWorldGetNative(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline("Testing getting the native world through Integ API");
+
+  Matrix         transform(true);
+  Uint16Pair     size(640, 480);
+  PhysicsAdaptor adaptor   = PhysicsAdaptor::New(transform, size);
+  Actor          rootActor = adaptor.GetRootActor();
+  auto           scene     = application.GetScene();
+  scene.Add(rootActor);
+
+  Dali::Actor ballActor = Toolkit::ImageView::New(BALL_IMAGE);
+
+  cpBody*      body{nullptr};
+  PhysicsActor physicsActor;
+  {
+    auto accessor = adaptor.GetPhysicsAccessor();
+    auto space    = accessor->GetNative().Get<cpSpace*>();
+    body          = CreateBody(space);
+    physicsActor  = adaptor.AddActorBody(ballActor, body);
+  }
+
+  DALI_TEST_CHECK(adaptor);
+  Dali::Toolkit::Physics::Integration::PhysicsWorld world = Dali::Toolkit::Physics::Integration::GetPhysicsWorld(adaptor);
+
+  world.Lock();
+  cpBody* newBody{nullptr};
+  try
+  {
+    auto     worldImpl = world.GetNative();
+    cpSpace* space     = worldImpl.Get<cpSpace*>();
+    DALI_TEST_CHECK(space != nullptr);
+
+    newBody = CreateHexBody(space);
+  }
+  catch(DaliException& e)
+  {
+    tet_result(TET_FAIL);
+  }
+  world.Unlock();
+
+  DALI_TEST_CHECK(newBody != nullptr);
+  END_TEST;
+}
+
+int UtcDaliPhysics2DIntegrationPhysicsWorldHitTest(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline("Testing the Hit Test works through Integ API");
+
+  const Vector2 center(TestApplication::DEFAULT_SURFACE_WIDTH * 0.5f, TestApplication::DEFAULT_SURFACE_HEIGHT * 0.5f);
+
+  Matrix         transform(true);
+  Uint16Pair     size(640, 480);
+  PhysicsAdaptor adaptor   = PhysicsAdaptor::New(transform, size);
+  Actor          rootActor = adaptor.GetRootActor();
+  auto           scene     = application.GetScene();
+  scene.Add(rootActor);
+
+  Dali::Actor ballActor = Toolkit::ImageView::New(BALL_IMAGE);
+
+  cpBody*      body{nullptr};
+  PhysicsActor physicsActor;
+  {
+    auto accessor = adaptor.GetPhysicsAccessor();
+    auto space    = accessor->GetNative().Get<cpSpace*>();
+    body          = CreateBody(space);
+    physicsActor  = adaptor.AddActorBody(ballActor, body);
+  }
+
+  DALI_TEST_CHECK(adaptor);
+
+  Vector3 from, to;
+  adaptor.BuildPickingRay(Vector3(center), Vector3(center), from, to);
+
+  Dali::Toolkit::Physics::Integration::PhysicsWorld world = Dali::Toolkit::Physics::Integration::GetPhysicsWorld(adaptor);
+  world.Lock();
+  try
+  {
+    auto     worldImpl = world.GetNative();
+    cpSpace* space     = worldImpl.Get<cpSpace*>();
+    DALI_TEST_CHECK(space != nullptr);
+
+    cpShapeFilter GRAB_FILTER = {CP_NO_GROUP, 1u << 31, 1u << 31};
+    Dali::Any     nativeFilter{GRAB_FILTER};
+    Vector3       localPivot;
+    float         distanceFromCamera;
+    auto          body = world.HitTest(from, from, nativeFilter, localPivot, distanceFromCamera);
+
+    DALI_TEST_CHECK(!body.Empty());
+    cpBody* cbody = body.Get<cpBody*>();
+
+    DALI_TEST_CHECK(cbody != nullptr);
+  }
+  catch(DaliException& e)
+  {
+    tet_result(TET_FAIL);
+  }
+  world.Unlock();
+
+  END_TEST;
+}
index 9c52173..63f4b9e 100644 (file)
@@ -72,17 +72,20 @@ add_subdirectory("${physics_dir}/third-party/bullet3" bullet3)
 
 set(physics_src_files "")
 include(${physics_dir}/public-api/file.list)
+include(${physics_dir}/integration-api/file.list)
+# Must come last!
 include(${physics_dir}/internal/file.list)
 
 set(prefix_include_dir "${prefix}/include")
 
 include_directories(BEFORE
   ${repo_root_dir}
-  "${prefix_include_dir}"
   "${repo_root_dir}/dali-physics/third-party/bullet3/src"
   "${repo_root_dir}/dali-physics/third-party/chipmunk2d/include"
 )
 
+include_directories(AFTER "${prefix_include_dir}")
+
 MESSAGE(STATUS "2D sources: ${physics2d_src_files}")
 MESSAGE(STATUS "3D sources: ${physics3d_src_files}")
 
@@ -182,6 +185,9 @@ ENDIF()
 install( FILES ${physics_public_api_header_files}
   DESTINATION "${INCLUDE_DIR}/dali-physics/public-api"
   )
+install( FILES ${physics_integration_api_header_files}
+  DESTINATION "${INCLUDE_DIR}/dali-physics/integration-api"
+  )
 
 install( FILES ${physics_dir}/dali-physics.h
   DESTINATION "${INCLUDE_DIR}/dali-physics"
diff --git a/dali-physics/integration-api/file.list b/dali-physics/integration-api/file.list
new file mode 100644 (file)
index 0000000..bc85da7
--- /dev/null
@@ -0,0 +1,11 @@
+set(physics_integration_api_dir "${physics_dir}/integration-api")
+
+set(physics_src_files ${physics_src_files}
+       ${physics_integration_api_dir}/integ-physics-adaptor.cpp
+       ${physics_integration_api_dir}/physics-world.cpp
+)
+
+set(physics_integration_api_header_files
+       ${physics_integration_api_dir}/integ-physics-adaptor.h
+       ${physics_integration_api_dir}/physics-world.h
+)
diff --git a/dali-physics/integration-api/integ-physics-adaptor.cpp b/dali-physics/integration-api/integ-physics-adaptor.cpp
new file mode 100644 (file)
index 0000000..cc26338
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * 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.
+ */
+
+#include <dali-physics/integration-api/integ-physics-adaptor.h>
+
+#include <dali-physics/internal/physics-adaptor-impl.h>
+#include <memory>
+
+namespace Dali::Toolkit::Physics::Integration
+{
+Integration::PhysicsWorld GetPhysicsWorld(PhysicsAdaptor adaptorHandle)
+{
+  std::unique_ptr<Internal::PhysicsWorld>& worldPtr = GetImplementation(adaptorHandle).GetPhysicsWorld();
+  return PhysicsWorld{worldPtr.get()};
+}
+
+} // namespace Dali::Toolkit::Physics::Integration
diff --git a/dali-physics/integration-api/integ-physics-adaptor.h b/dali-physics/integration-api/integ-physics-adaptor.h
new file mode 100644 (file)
index 0000000..38edd37
--- /dev/null
@@ -0,0 +1,27 @@
+#pragma once
+
+/*
+ * 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.
+ */
+
+#include <dali-physics/integration-api/physics-world.h>
+
+#include <dali-physics/public-api/physics-adaptor.h>
+
+namespace Dali::Toolkit::Physics::Integration
+{
+Integration::PhysicsWorld GetPhysicsWorld(PhysicsAdaptor adaptorHandle);
+
+} // namespace Dali::Toolkit::Physics::Integration
diff --git a/dali-physics/integration-api/physics-world.cpp b/dali-physics/integration-api/physics-world.cpp
new file mode 100644 (file)
index 0000000..b17fa5c
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * 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.
+ */
+
+#include <dali-physics/integration-api/physics-world.h>
+#include <dali-physics/internal/physics-world-impl.h>
+#include <dali/public-api/common/dali-common.h>
+
+namespace Dali::Toolkit::Physics::Integration
+{
+PhysicsWorld::PhysicsWorld(Dali::Toolkit::Physics::Internal::PhysicsWorld* internalWorld)
+: impl(internalWorld)
+{
+}
+
+PhysicsWorld::~PhysicsWorld() = default;
+
+Dali::Toolkit::Physics::Internal::PhysicsWorld* PhysicsWorld::GetImpl()
+{
+  return impl;
+}
+
+void PhysicsWorld::Lock()
+{
+  DALI_ASSERT_ALWAYS(impl && "Physics world proxy has null impl");
+  impl->Lock();
+}
+
+void PhysicsWorld::Unlock()
+{
+  DALI_ASSERT_ALWAYS(impl && "Physics world proxy has null impl");
+  impl->Unlock();
+}
+
+Dali::Any PhysicsWorld::GetNative()
+{
+  DALI_ASSERT_ALWAYS(impl && "Physics world proxy has null impl");
+  return impl->GetNative();
+}
+
+Dali::Any PhysicsWorld::HitTest(Dali::Vector3 rayFromWorld, Dali::Vector3 rayToWorld, Dali::Any nativeFilter, Dali::Vector3& localPivot, float& distanceFromCamera)
+
+{
+  DALI_ASSERT_ALWAYS(impl && "Physics world proxy has null impl");
+  return impl->HitTest(rayFromWorld, rayToWorld, nativeFilter, localPivot, distanceFromCamera);
+}
+
+} // namespace Dali::Toolkit::Physics::Integration
diff --git a/dali-physics/integration-api/physics-world.h b/dali-physics/integration-api/physics-world.h
new file mode 100644 (file)
index 0000000..bf56e40
--- /dev/null
@@ -0,0 +1,102 @@
+#pragma once
+
+/*
+ * 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.
+ */
+#include <dali-toolkit/public-api/dali-toolkit-common.h>
+#include <dali/public-api/math/vector3.h>
+#include <dali/public-api/object/any.h>
+
+namespace Dali::Toolkit::Physics::Internal
+{
+class PhysicsWorld;
+}
+
+namespace Dali::Toolkit::Physics::Integration
+{
+/** Proxy to the physics world impl.
+ *
+ * Does NOT own physics world.
+ * Copyable. Doesn't track lock.
+ */
+class DALI_TOOLKIT_API PhysicsWorld
+{
+public:
+  /**
+   * Constructor
+   * @param[in] impl The physics world implementation class.
+   */
+  PhysicsWorld(Dali::Toolkit::Physics::Internal::PhysicsWorld* impl);
+
+  /**
+   * Destructor.
+   * Does not destroy the physic world.
+   */
+  ~PhysicsWorld();
+
+  /**
+   * Copy Constructor
+   */
+  PhysicsWorld(const PhysicsWorld& rhs) = default;
+
+  /**
+   * Assignment operator
+   */
+  PhysicsWorld& operator=(const PhysicsWorld& rhs) = default;
+
+  /**
+   * Lock the physics world. The caller MUST unlock it afterwards, otherwise
+   * the physics integration step will block, and DALi update thread will be locked.
+   */
+  void Lock();
+
+  /**
+   * Unlock the physics world.
+   */
+  void Unlock();
+
+  /**
+   * Get a handle to the native physics world / space
+   *
+   * This API should be wrapped with Lock/Unlock in any interop implementation
+   * @return a pointer to the native world.
+   */
+  Dali::Any GetNative();
+
+  /**
+   * Hit test the physics world.
+   *
+   * This API should be wrapped with Lock/Unlock in any interop implementation
+   * @param[in] rayFromWorld The origin in physics world space
+   * @param[in] rayToWorld A point along the direction on the far side of the physics world
+   * @param[in] nativeFilter a native body / shape filter
+   * @param[out] localPivot The hit point local to the body
+   * @param[out] distanceFromCamera The distance of the pick point from the camera
+   * @return Either a pointer to the native body, or an empty value.
+   */
+  Dali::Any HitTest(Dali::Vector3 rayFromWorld, Dali::Vector3 rayToWorld, Dali::Any nativeFilter, Dali::Vector3& localPivot, float& distanceFromCamera);
+
+  /**
+   * Get the implementation pointer.
+   *
+   * @return the implementation pointer.
+   */
+  Dali::Toolkit::Physics::Internal::PhysicsWorld* GetImpl();
+
+private:
+  Dali::Toolkit::Physics::Internal::PhysicsWorld* impl;
+};
+
+} // namespace Dali::Toolkit::Physics::Integration
index 920d015..63c000d 100644 (file)
@@ -54,7 +54,7 @@ void BulletPhysicsWorld::OnInitialize(/*void* dynamicsWorld*/)
 
 BulletPhysicsWorld::~BulletPhysicsWorld()
 {
-  Dali::Mutex::ScopedLock lock(mMutex);
+  Lock();
 
   if(mDynamicsWorld)
   {
@@ -76,20 +76,15 @@ BulletPhysicsWorld::~BulletPhysicsWorld()
     }
   }
 
-  /*
-  for (int j = 0; j < m_collisionShapes.size(); j++)
-  {
-    btCollisionShape* shape = mCollisionShapes[j];
-    delete shape;
-  }
-  mCollisionShapes.clear();
-  */
+  // @todo Should clear down known collision shapes
 
   delete mDynamicsWorld;
   delete mSolver;
   delete mBroadphase;
   delete mDispatcher;
   delete mCollisionConfiguration;
+
+  Unlock();
 }
 
 Dali::Any BulletPhysicsWorld::GetNative()
index eee9cd4..3cb98f6 100644 (file)
@@ -54,7 +54,7 @@ PhysicsActor::~PhysicsActor() = default;
 
 void PhysicsActor::Initialize(void)
 {
-  cpBodySetUserData(mBody.Get<cpBody*>(), this);
+  cpBodySetUserData2(mBody.Get<cpBody*>(), this);
 
   // RegisterObject?
 }
index 923927a..b909890 100644 (file)
@@ -131,7 +131,7 @@ PhysicsActorPtr ChipmunkPhysicsAdaptor::AddActorBody(Dali::Actor actor, Dali::An
 {
   uint32_t id    = static_cast<uint32_t>(actor.GetProperty<int>(Actor::Property::ID));
   cpBody*  cBody = body.Get<cpBody*>();
-  cpBodySetUserData(cBody, this);
+  cpBodySetUserData2(cBody, this);
 
   mPhysicsActors.insert(std::make_pair(id, PhysicsActor::New(actor, body, *this)));
   actor[Actor::Property::PARENT_ORIGIN] = Dali::ParentOrigin::CENTER;
@@ -156,7 +156,7 @@ void ChipmunkPhysicsAdaptor::RemoveActorBody(PhysicsActor& physicsActor)
   cpBody* cBody = body.Get<cpBody*>();
   if(cBody)
   {
-    cpBodySetUserData(cBody, nullptr);
+    cpBodySetUserData2(cBody, nullptr);
   }
 }
 
@@ -165,7 +165,7 @@ PhysicsActorPtr ChipmunkPhysicsAdaptor::GetPhysicsActor(Dali::Any body) const
   cpBody* cBody = body.Get<cpBody*>();
   if(cBody)
   {
-    return reinterpret_cast<PhysicsActor*>(cpBodyGetUserData(cBody));
+    return reinterpret_cast<PhysicsActor*>(cpBodyGetUserData2(cBody));
   }
   DALI_LOG_ERROR("Body not found in physics actors");
   return nullptr;
index 7423edd..353dc7f 100644 (file)
@@ -90,7 +90,7 @@ void ChipmunkPhysicsWorld::OnInitialize(/*void* dynamicsWorld*/)
 
 ChipmunkPhysicsWorld::~ChipmunkPhysicsWorld()
 {
-  Dali::Mutex::ScopedLock lock(mMutex);
+  Lock();
   if(mSpace)
   {
     cpSpaceEachShape(mSpace, (cpSpaceShapeIteratorFunc)PostShapeFree, mSpace);
@@ -99,6 +99,7 @@ ChipmunkPhysicsWorld::~ChipmunkPhysicsWorld()
     cpSpaceFree(mSpace);
     mSpace = nullptr;
   }
+  Unlock();
 }
 
 Dali::Any ChipmunkPhysicsWorld::GetNative()
index 09b3408..e9bfe82 100644 (file)
@@ -125,4 +125,9 @@ void PhysicsAdaptor::CreateSyncPoint()
   mPhysicsWorld->CreateSyncPoint();
 }
 
+std::unique_ptr<PhysicsWorld>& PhysicsAdaptor::GetPhysicsWorld()
+{
+  return mPhysicsWorld;
+}
+
 } // namespace Dali::Toolkit::Physics::Internal
index 02e651a..fb3939b 100644 (file)
@@ -179,6 +179,8 @@ public:
    */
   void OnUpdateActors(Dali::UpdateProxy* updateProxy);
 
+  std::unique_ptr<PhysicsWorld>& GetPhysicsWorld();
+
 protected:
   std::unique_ptr<PhysicsWorld>                 mPhysicsWorld;
   std::unordered_map<uint32_t, PhysicsActorPtr> mPhysicsActors;
index b0ca04d..41da002 100644 (file)
@@ -24,6 +24,8 @@
 #include <dali/devel-api/common/stage-devel.h>
 #include <dali/devel-api/update/frame-callback-interface.h>
 
+thread_local int gLocked{0};
+
 namespace Dali::Toolkit::Physics::Internal
 {
 /**
@@ -83,14 +85,9 @@ PhysicsWorld::~PhysicsWorld()
   Dali::DevelStage::RemoveFrameCallback(Dali::Stage::GetCurrent(), *mFrameCallback);
 }
 
-Dali::Mutex& PhysicsWorld::GetMutex()
-{
-  return mMutex;
-}
-
 bool PhysicsWorld::OnUpdate(Dali::UpdateProxy& updateProxy, float elapsedSeconds)
 {
-  Dali::Mutex::ScopedLock lock(mMutex);
+  ScopedLock lock(*this);
 
   // Process command queue
   if(mNotifySyncPoint != Dali::UpdateProxy::INVALID_SYNC &&
@@ -134,19 +131,35 @@ float PhysicsWorld::GetTimestep()
   return mPhysicsTimeStep;
 }
 
-void PhysicsWorld::Queue(std::function<void(void)> function)
+/**
+ * Lock the mutex.
+ */
+void PhysicsWorld::Lock()
 {
-  if(!mMutex.IsLocked()) // Annoyingly, the dali mutex scoped lock doesn't prevent relocking in the same thread.
-  {
-    Dali::Mutex::ScopedLock lock(mMutex);
-    commandQueue.push(function);
-  }
-  else
+  //@todo Could replace the mutex with an atomic flag, if it's not set,
+  // the queue and integration step could be skipped
+  if(!gLocked)
   {
-    commandQueue.push(function);
+    gLocked = true;
+    mMutex.lock();
   }
 }
 
+/**
+ * Unlock the mutex
+ */
+void PhysicsWorld::Unlock()
+{
+  mMutex.unlock();
+  gLocked = false;
+}
+
+void PhysicsWorld::Queue(std::function<void(void)> function)
+{
+  ScopedLock lock(*this);
+  commandQueue.push(function);
+}
+
 void PhysicsWorld::CreateSyncPoint()
 {
   mNotifySyncPoint = Dali::DevelStage::NotifyFrameCallback(Dali::Stage::GetCurrent(), *mFrameCallback);
index b1c9460..f14f546 100644 (file)
  */
 
 #include <dali/dali.h>
-#include <dali/devel-api/threading/mutex.h>
 #include <dali/devel-api/update/frame-callback-interface.h>
 #include <dali/devel-api/update/update-proxy.h>
 
 #include <dali-physics/public-api/physics-adaptor.h>
 
 #include <functional>
+#include <mutex>
 #include <queue>
 
 namespace Dali::Toolkit::Physics::Internal
@@ -89,6 +89,31 @@ public:
   float GetTimestep();
 
   /**
+   * Lock the mutex.
+   */
+  void Lock();
+
+  /**
+   * Unlock the mutex
+   */
+  void Unlock();
+
+  class ScopedLock
+  {
+  public:
+    ScopedLock(PhysicsWorld& world)
+    : mWorld(world)
+    {
+      mWorld.Lock();
+    }
+    ~ScopedLock()
+    {
+      mWorld.Unlock();
+    }
+    PhysicsWorld& mWorld;
+  };
+
+  /**
    * Queue a function for execution in the update thread, prior to the physics integration.
    * Enables syncronization of DALi properties and physics controlled properties.
    */
@@ -139,15 +164,13 @@ public:
   Physics::PhysicsAdaptor::DebugState GetDebugState();
 
 public:
-  Dali::Mutex& GetMutex(); // Only for use by adaptor in creating scoped accessor
-
   bool OnUpdate(Dali::UpdateProxy& updateProxy, float elapsedSeconds);
 
 protected:
   virtual void Integrate(float timestep) = 0;
 
 protected:
-  Dali::Mutex                           mMutex;
+  std::mutex                            mMutex;
   std::queue<std::function<void(void)>> commandQueue;
   Dali::UpdateProxy::NotifySyncPoint    mNotifySyncPoint{Dali::UpdateProxy::INVALID_SYNC};
   Dali::CallbackBase*                   mUpdateCallback{nullptr};
index 1fad04c..e0804f8 100644 (file)
@@ -24,14 +24,17 @@ namespace Dali::Toolkit::Physics
 struct PhysicsAdaptor::ScopedPhysicsAccessor::Impl
 {
   Impl(Internal::PhysicsWorld& world)
-  : mLock(world.GetMutex()),
-    mPhysicsWorld(world)
+  : mPhysicsWorld(world)
   {
+    mPhysicsWorld.Lock();
   }
   Impl(Impl&)         = delete;
   const Impl& operator=(const Impl&) = delete;
 
-  Dali::Mutex::ScopedLock mLock;
+  ~Impl()
+  {
+    mPhysicsWorld.Unlock();
+  }
   Internal::PhysicsWorld& mPhysicsWorld;
   friend Internal::PhysicsAdaptor;
 };
index d8b1e6f..d5efa19 100644 (file)
@@ -61,6 +61,7 @@ struct cpBody {
        cpTransform transform;
        
        cpDataPointer userData;
+       cpDataPointer userData2;
        
        // "pseudo-velocities" used for eliminating overlap.
        // Erin Catto has some papers that talk about what these are.
index 8e46cc3..db7a9ea 100644 (file)
@@ -140,6 +140,11 @@ CP_EXPORT cpDataPointer cpBodyGetUserData(const cpBody *body);
 /// Set the user data pointer assigned to the body.
 CP_EXPORT void cpBodySetUserData(cpBody *body, cpDataPointer userData);
 
+/// Get the 2nd user data pointer assigned to the body.
+CP_EXPORT cpDataPointer cpBodyGetUserData2(const cpBody *body);
+/// Set the 2nd user data pointer assigned to the body.
+CP_EXPORT void cpBodySetUserData2(cpBody *body, cpDataPointer userData);
+
 /// Set the callback used to update a body's velocity.
 CP_EXPORT void cpBodySetVelocityUpdateFunc(cpBody *body, cpBodyVelocityFunc velocityFunc);
 /// Set the callback used to update a body's position.
index 55f7954..5c30d43 100644 (file)
@@ -1,7 +1,7 @@
 file(GLOB chipmunk_source_files "*.c")
 file(GLOB chipmunk_public_header "${chipmunk_SOURCE_DIR}/include/chipmunk/*.h")
 
-include_directories(${chipmunk_SOURCE_DIR}/include)
+include_directories(BEFORE ${chipmunk_SOURCE_DIR}/include)
 
 # Chipmunk2D 7.0.3
 set(CHIPMUNK_VERSION_MAJOR 7)
index e5caaf9..3d2bb1c 100644 (file)
@@ -56,6 +56,7 @@ cpBodyInit(cpBody *body, cpFloat mass, cpFloat moment)
        body->w_bias = 0.0f;
        
        body->userData = NULL;
+       body->userData2 = NULL;
        
        // Setters must be called after full initialization so the sanity checks don't assert on garbage data.
        cpBodySetMass(body, mass);
@@ -483,6 +484,17 @@ cpBodySetUserData(cpBody *body, cpDataPointer userData)
 {
        body->userData = userData;
 }
+cpDataPointer
+cpBodyGetUserData2(const cpBody *body)
+{
+       return body->userData2;
+}
+
+void
+cpBodySetUserData2(cpBody *body, cpDataPointer userData)
+{
+       body->userData2 = userData;
+}
 
 void
 cpBodySetVelocityUpdateFunc(cpBody *body, cpBodyVelocityFunc velocityFunc)
index da90ed7..8db2b8d 100644 (file)
@@ -549,6 +549,7 @@ esac
 
 %files -n %{dali2_physics2d}-devel
 %defattr(-,root,root,-)
+%{_includedir}/dali-physics/integration-api/*
 %{_includedir}/dali-physics/public-api/*
 %{_includedir}/dali-physics/dali-physics.h
 %{_includedir}/chipmunk/*
@@ -568,6 +569,7 @@ esac
 
 %files -n %{dali2_physics3d}-devel
 %defattr(-,root,root,-)
+%{_includedir}/dali-physics/integration-api/*
 %{_includedir}/dali-physics/public-api/*
 %{_includedir}/dali-physics/dali-physics.h
 %{_includedir}/bullet/*