From 8413f5e2f7fd782c3e44cf94e5fcdd55cd0975ad Mon Sep 17 00:00:00 2001 From: David Steele Date: Mon, 11 Sep 2023 18:37:30 +0100 Subject: [PATCH] Added integration api to physics 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 --- automated-tests/src/dali-physics2d/CMakeLists.txt | 1 + .../src/dali-physics2d/utc-Dali-IntegPhysics.cpp | 239 +++++++++++++++++++++ build/tizen/dali-physics/CMakeLists.txt | 8 +- dali-physics/integration-api/file.list | 11 + .../integration-api/integ-physics-adaptor.cpp | 30 +++ .../integration-api/integ-physics-adaptor.h | 27 +++ dali-physics/integration-api/physics-world.cpp | 60 ++++++ dali-physics/integration-api/physics-world.h | 102 +++++++++ .../bullet-impl/bullet-physics-world-impl.cpp | 13 +- .../chipmunk-impl/chipmunk-physics-actor-impl.cpp | 2 +- .../chipmunk-physics-adaptor-impl.cpp | 6 +- .../chipmunk-impl/chipmunk-physics-world-impl.cpp | 3 +- dali-physics/internal/physics-adaptor-impl.cpp | 5 + dali-physics/internal/physics-adaptor-impl.h | 2 + dali-physics/internal/physics-world-impl.cpp | 41 ++-- dali-physics/internal/physics-world-impl.h | 31 ++- .../public-api/scoped-physics-accessor.cpp | 9 +- .../chipmunk2d/include/chipmunk/chipmunk_structs.h | 1 + .../chipmunk2d/include/chipmunk/cpBody.h | 5 + .../third-party/chipmunk2d/src/CMakeLists.txt | 2 +- dali-physics/third-party/chipmunk2d/src/cpBody.c | 12 ++ packaging/dali-toolkit.spec | 2 + 22 files changed, 575 insertions(+), 37 deletions(-) create mode 100644 automated-tests/src/dali-physics2d/utc-Dali-IntegPhysics.cpp create mode 100644 dali-physics/integration-api/file.list create mode 100644 dali-physics/integration-api/integ-physics-adaptor.cpp create mode 100644 dali-physics/integration-api/integ-physics-adaptor.h create mode 100644 dali-physics/integration-api/physics-world.cpp create mode 100644 dali-physics/integration-api/physics-world.h diff --git a/automated-tests/src/dali-physics2d/CMakeLists.txt b/automated-tests/src/dali-physics2d/CMakeLists.txt index ea0f140..e796089 100644 --- a/automated-tests/src/dali-physics2d/CMakeLists.txt +++ b/automated-tests/src/dali-physics2d/CMakeLists.txt @@ -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 index 0000000..c79c495 --- /dev/null +++ b/automated-tests/src/dali-physics2d/utc-Dali-IntegPhysics.cpp @@ -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 +#include +#include + +// Need to override adaptor classes for toolkit test harness, so include +// test harness headers before dali headers. +#include + +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include + +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(); + 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(); + 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(); + 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(); + 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(); + 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(); + + DALI_TEST_CHECK(cbody != nullptr); + } + catch(DaliException& e) + { + tet_result(TET_FAIL); + } + world.Unlock(); + + END_TEST; +} diff --git a/build/tizen/dali-physics/CMakeLists.txt b/build/tizen/dali-physics/CMakeLists.txt index 9c52173..63f4b9e 100644 --- a/build/tizen/dali-physics/CMakeLists.txt +++ b/build/tizen/dali-physics/CMakeLists.txt @@ -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 index 0000000..bc85da7 --- /dev/null +++ b/dali-physics/integration-api/file.list @@ -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 index 0000000..cc26338 --- /dev/null +++ b/dali-physics/integration-api/integ-physics-adaptor.cpp @@ -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 + +#include +#include + +namespace Dali::Toolkit::Physics::Integration +{ +Integration::PhysicsWorld GetPhysicsWorld(PhysicsAdaptor adaptorHandle) +{ + std::unique_ptr& 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 index 0000000..38edd37 --- /dev/null +++ b/dali-physics/integration-api/integ-physics-adaptor.h @@ -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 + +#include + +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 index 0000000..b17fa5c --- /dev/null +++ b/dali-physics/integration-api/physics-world.cpp @@ -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 +#include +#include + +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 index 0000000..bf56e40 --- /dev/null +++ b/dali-physics/integration-api/physics-world.h @@ -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 +#include +#include + +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 diff --git a/dali-physics/internal/bullet-impl/bullet-physics-world-impl.cpp b/dali-physics/internal/bullet-impl/bullet-physics-world-impl.cpp index 920d015..63c000d 100644 --- a/dali-physics/internal/bullet-impl/bullet-physics-world-impl.cpp +++ b/dali-physics/internal/bullet-impl/bullet-physics-world-impl.cpp @@ -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() diff --git a/dali-physics/internal/chipmunk-impl/chipmunk-physics-actor-impl.cpp b/dali-physics/internal/chipmunk-impl/chipmunk-physics-actor-impl.cpp index eee9cd4..3cb98f6 100644 --- a/dali-physics/internal/chipmunk-impl/chipmunk-physics-actor-impl.cpp +++ b/dali-physics/internal/chipmunk-impl/chipmunk-physics-actor-impl.cpp @@ -54,7 +54,7 @@ PhysicsActor::~PhysicsActor() = default; void PhysicsActor::Initialize(void) { - cpBodySetUserData(mBody.Get(), this); + cpBodySetUserData2(mBody.Get(), this); // RegisterObject? } diff --git a/dali-physics/internal/chipmunk-impl/chipmunk-physics-adaptor-impl.cpp b/dali-physics/internal/chipmunk-impl/chipmunk-physics-adaptor-impl.cpp index 923927a..b909890 100644 --- a/dali-physics/internal/chipmunk-impl/chipmunk-physics-adaptor-impl.cpp +++ b/dali-physics/internal/chipmunk-impl/chipmunk-physics-adaptor-impl.cpp @@ -131,7 +131,7 @@ PhysicsActorPtr ChipmunkPhysicsAdaptor::AddActorBody(Dali::Actor actor, Dali::An { uint32_t id = static_cast(actor.GetProperty(Actor::Property::ID)); cpBody* cBody = body.Get(); - 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(); if(cBody) { - cpBodySetUserData(cBody, nullptr); + cpBodySetUserData2(cBody, nullptr); } } @@ -165,7 +165,7 @@ PhysicsActorPtr ChipmunkPhysicsAdaptor::GetPhysicsActor(Dali::Any body) const cpBody* cBody = body.Get(); if(cBody) { - return reinterpret_cast(cpBodyGetUserData(cBody)); + return reinterpret_cast(cpBodyGetUserData2(cBody)); } DALI_LOG_ERROR("Body not found in physics actors"); return nullptr; diff --git a/dali-physics/internal/chipmunk-impl/chipmunk-physics-world-impl.cpp b/dali-physics/internal/chipmunk-impl/chipmunk-physics-world-impl.cpp index 7423edd..353dc7f 100644 --- a/dali-physics/internal/chipmunk-impl/chipmunk-physics-world-impl.cpp +++ b/dali-physics/internal/chipmunk-impl/chipmunk-physics-world-impl.cpp @@ -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() diff --git a/dali-physics/internal/physics-adaptor-impl.cpp b/dali-physics/internal/physics-adaptor-impl.cpp index 09b3408..e9bfe82 100644 --- a/dali-physics/internal/physics-adaptor-impl.cpp +++ b/dali-physics/internal/physics-adaptor-impl.cpp @@ -125,4 +125,9 @@ void PhysicsAdaptor::CreateSyncPoint() mPhysicsWorld->CreateSyncPoint(); } +std::unique_ptr& PhysicsAdaptor::GetPhysicsWorld() +{ + return mPhysicsWorld; +} + } // namespace Dali::Toolkit::Physics::Internal diff --git a/dali-physics/internal/physics-adaptor-impl.h b/dali-physics/internal/physics-adaptor-impl.h index 02e651a..fb3939b 100644 --- a/dali-physics/internal/physics-adaptor-impl.h +++ b/dali-physics/internal/physics-adaptor-impl.h @@ -179,6 +179,8 @@ public: */ void OnUpdateActors(Dali::UpdateProxy* updateProxy); + std::unique_ptr& GetPhysicsWorld(); + protected: std::unique_ptr mPhysicsWorld; std::unordered_map mPhysicsActors; diff --git a/dali-physics/internal/physics-world-impl.cpp b/dali-physics/internal/physics-world-impl.cpp index b0ca04d..41da002 100644 --- a/dali-physics/internal/physics-world-impl.cpp +++ b/dali-physics/internal/physics-world-impl.cpp @@ -24,6 +24,8 @@ #include #include +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 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 function) +{ + ScopedLock lock(*this); + commandQueue.push(function); +} + void PhysicsWorld::CreateSyncPoint() { mNotifySyncPoint = Dali::DevelStage::NotifyFrameCallback(Dali::Stage::GetCurrent(), *mFrameCallback); diff --git a/dali-physics/internal/physics-world-impl.h b/dali-physics/internal/physics-world-impl.h index b1c9460..f14f546 100644 --- a/dali-physics/internal/physics-world-impl.h +++ b/dali-physics/internal/physics-world-impl.h @@ -18,13 +18,13 @@ */ #include -#include #include #include #include #include +#include #include 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> commandQueue; Dali::UpdateProxy::NotifySyncPoint mNotifySyncPoint{Dali::UpdateProxy::INVALID_SYNC}; Dali::CallbackBase* mUpdateCallback{nullptr}; diff --git a/dali-physics/public-api/scoped-physics-accessor.cpp b/dali-physics/public-api/scoped-physics-accessor.cpp index 1fad04c..e0804f8 100644 --- a/dali-physics/public-api/scoped-physics-accessor.cpp +++ b/dali-physics/public-api/scoped-physics-accessor.cpp @@ -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; }; diff --git a/dali-physics/third-party/chipmunk2d/include/chipmunk/chipmunk_structs.h b/dali-physics/third-party/chipmunk2d/include/chipmunk/chipmunk_structs.h index d8b1e6f..d5efa19 100644 --- a/dali-physics/third-party/chipmunk2d/include/chipmunk/chipmunk_structs.h +++ b/dali-physics/third-party/chipmunk2d/include/chipmunk/chipmunk_structs.h @@ -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. diff --git a/dali-physics/third-party/chipmunk2d/include/chipmunk/cpBody.h b/dali-physics/third-party/chipmunk2d/include/chipmunk/cpBody.h index 8e46cc3..db7a9ea 100644 --- a/dali-physics/third-party/chipmunk2d/include/chipmunk/cpBody.h +++ b/dali-physics/third-party/chipmunk2d/include/chipmunk/cpBody.h @@ -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. diff --git a/dali-physics/third-party/chipmunk2d/src/CMakeLists.txt b/dali-physics/third-party/chipmunk2d/src/CMakeLists.txt index 55f7954..5c30d43 100644 --- a/dali-physics/third-party/chipmunk2d/src/CMakeLists.txt +++ b/dali-physics/third-party/chipmunk2d/src/CMakeLists.txt @@ -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) diff --git a/dali-physics/third-party/chipmunk2d/src/cpBody.c b/dali-physics/third-party/chipmunk2d/src/cpBody.c index e5caaf9..3d2bb1c 100644 --- a/dali-physics/third-party/chipmunk2d/src/cpBody.c +++ b/dali-physics/third-party/chipmunk2d/src/cpBody.c @@ -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) diff --git a/packaging/dali-toolkit.spec b/packaging/dali-toolkit.spec index da90ed7..8db2b8d 100644 --- a/packaging/dali-toolkit.spec +++ b/packaging/dali-toolkit.spec @@ -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/* -- 2.7.4