From: David Steele Date: Tue, 22 Aug 2023 13:13:20 +0000 (+0100) Subject: Adding chipmunk implementation for physics adaptor X-Git-Tag: dali_2.2.43~4^2 X-Git-Url: http://review.tizen.org/git/?p=platform%2Fcore%2Fuifw%2Fdali-toolkit.git;a=commitdiff_plain;h=537c38c0fc284ad7c61b8d815a9d4ec9f3ab4edc Adding chipmunk implementation for physics adaptor Splitting out common implementation for PhysicsWorld and Physicsadaptor to base classes. Split out test cases into dali-physics2d & dali-physics3d sets Change-Id: I776588c1d4845cda450f0c95ad455097400d9a17 Signed-off-by: David Steele --- diff --git a/automated-tests/src/dali-physics2d/CMakeLists.txt b/automated-tests/src/dali-physics2d/CMakeLists.txt new file mode 100644 index 0000000..ea0f140 --- /dev/null +++ b/automated-tests/src/dali-physics2d/CMakeLists.txt @@ -0,0 +1,97 @@ +SET(PKG_NAME "dali-physics2d") + +SET(EXEC_NAME "tct-${PKG_NAME}-core") +SET(RPM_NAME "core-${PKG_NAME}-tests") + +# List of test case sources (Only these get parsed for test cases) +SET(TC_SOURCES + utc-Dali-PhysicsAdaptor.cpp + utc-Dali-PhysicsActor.cpp + ) + +# List of test harness files (Won't get parsed for test cases) +SET(TEST_HARNESS_DIR "../dali-toolkit/dali-toolkit-test-utils") + +SET(TEST_HARNESS_SOURCES + ${TEST_HARNESS_DIR}/toolkit-adaptor.cpp + ${TEST_HARNESS_DIR}/toolkit-application.cpp + ${TEST_HARNESS_DIR}/toolkit-direct-rendering-egl.cpp + ${TEST_HARNESS_DIR}/toolkit-event-thread-callback.cpp + ${TEST_HARNESS_DIR}/toolkit-environment-variable.cpp + ${TEST_HARNESS_DIR}/toolkit-input-method-context.cpp + ${TEST_HARNESS_DIR}/toolkit-input-method-options.cpp + ${TEST_HARNESS_DIR}/toolkit-lifecycle-controller.cpp + ${TEST_HARNESS_DIR}/toolkit-orientation.cpp + ${TEST_HARNESS_DIR}/toolkit-style-monitor.cpp + ${TEST_HARNESS_DIR}/toolkit-test-application.cpp + ${TEST_HARNESS_DIR}/toolkit-timer.cpp + ${TEST_HARNESS_DIR}/toolkit-trigger-event-factory.cpp + ${TEST_HARNESS_DIR}/toolkit-window.cpp + ${TEST_HARNESS_DIR}/toolkit-scene-holder.cpp + ${TEST_HARNESS_DIR}/dali-test-suite-utils.cpp + ${TEST_HARNESS_DIR}/dali-toolkit-test-suite-utils.cpp + ${TEST_HARNESS_DIR}/dummy-control.cpp + ${TEST_HARNESS_DIR}/mesh-builder.cpp + ${TEST_HARNESS_DIR}/test-actor-utils.cpp + ${TEST_HARNESS_DIR}/test-animation-data.cpp + ${TEST_HARNESS_DIR}/test-application.cpp + ${TEST_HARNESS_DIR}/test-button.cpp + ${TEST_HARNESS_DIR}/test-harness.cpp + ${TEST_HARNESS_DIR}/test-gesture-generator.cpp + ${TEST_HARNESS_DIR}/test-gl-abstraction.cpp + ${TEST_HARNESS_DIR}/test-graphics-sync-impl.cpp + ${TEST_HARNESS_DIR}/test-graphics-sync-object.cpp + ${TEST_HARNESS_DIR}/test-graphics-buffer.cpp + ${TEST_HARNESS_DIR}/test-graphics-command-buffer.cpp + ${TEST_HARNESS_DIR}/test-graphics-framebuffer.cpp + ${TEST_HARNESS_DIR}/test-graphics-controller.cpp + ${TEST_HARNESS_DIR}/test-graphics-texture.cpp + ${TEST_HARNESS_DIR}/test-graphics-sampler.cpp + ${TEST_HARNESS_DIR}/test-graphics-program.cpp + ${TEST_HARNESS_DIR}/test-graphics-pipeline.cpp + ${TEST_HARNESS_DIR}/test-graphics-shader.cpp + ${TEST_HARNESS_DIR}/test-graphics-reflection.cpp + ${TEST_HARNESS_DIR}/test-platform-abstraction.cpp + ${TEST_HARNESS_DIR}/test-render-controller.cpp + ${TEST_HARNESS_DIR}/test-trace-call-stack.cpp +) + +PKG_CHECK_MODULES(${PKG_NAME} REQUIRED + dali2-core + dali2-adaptor + dali2-toolkit + dali2-physics-2d + chipmunk2d +) + +ADD_COMPILE_OPTIONS( -O0 -ggdb --coverage -Wall -Werror -DDEBUG_ENABLED) +ADD_COMPILE_OPTIONS( ${${PKG_NAME}_CFLAGS_OTHER} ) + +ADD_DEFINITIONS(-DTEST_RESOURCE_DIR=\"${CMAKE_CURRENT_SOURCE_DIR}/../../resources\" ) + +FOREACH(directory ${${PKG_NAME}_LIBRARY_DIRS}) + SET(CMAKE_CXX_LINK_FLAGS "${CMAKE_CXX_LINK_FLAGS} -L${directory}") +ENDFOREACH(directory ${PKG_NAME_LIBRARY_DIRS}) + +INCLUDE_DIRECTORIES( + ../../../ + ${${PKG_NAME}_INCLUDE_DIRS} + ../dali-toolkit/dali-toolkit-test-utils +) + +ADD_CUSTOM_COMMAND( + COMMAND ${SCRIPT_DIR}/tcheadgen.sh ${EXEC_NAME}.h ${TC_SOURCES} + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + OUTPUT ${EXEC_NAME}.h + COMMENT "Generating test tables" + ) + +ADD_EXECUTABLE(${EXEC_NAME} ${EXEC_NAME}.h ${EXEC_NAME}.cpp ${TC_SOURCES} ${TEST_HARNESS_SOURCES}) +TARGET_LINK_LIBRARIES(${EXEC_NAME} + ${${PKG_NAME}_LIBRARIES} + -lpthread -ldl --coverage +) + +INSTALL(PROGRAMS ${EXEC_NAME} + DESTINATION ${BIN_DIR}/${EXEC_NAME} +) diff --git a/automated-tests/src/dali-physics/tct-dali-physics-core.cpp b/automated-tests/src/dali-physics2d/tct-dali-physics2d-core.cpp similarity index 52% rename from automated-tests/src/dali-physics/tct-dali-physics-core.cpp rename to automated-tests/src/dali-physics2d/tct-dali-physics2d-core.cpp index 64550a1..b3297ce 100644 --- a/automated-tests/src/dali-physics/tct-dali-physics-core.cpp +++ b/automated-tests/src/dali-physics2d/tct-dali-physics2d-core.cpp @@ -1,7 +1,8 @@ #include -#include "tct-dali-physics-core.h" -int main(int argc, char * const argv[]) +#include "tct-dali-physics2d-core.h" + +int main(int argc, char* const argv[]) { return TestHarness::RunTests(argc, argv, tc_array); } diff --git a/automated-tests/src/dali-physics2d/utc-Dali-PhysicsActor.cpp b/automated-tests/src/dali-physics2d/utc-Dali-PhysicsActor.cpp new file mode 100644 index 0000000..855d686 --- /dev/null +++ b/automated-tests/src/dali-physics2d/utc-Dali-PhysicsActor.cpp @@ -0,0 +1,595 @@ +/* + * 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 + +using namespace Dali; +using namespace Dali::Toolkit::Physics; + +extern cpBody* CreateBody(cpSpace* space); + +const char* BALL_IMAGE = TEST_RESOURCE_DIR "/gallery-small-1.jpg"; + +int UtcDaliPhysics2DActorNew(void) +{ + ToolkitTestApplication application; + + cpBody* body{nullptr}; + + Matrix transform(true); + Uint16Pair size(640, 480); + PhysicsAdaptor adaptor = PhysicsAdaptor::New(transform, size); + + auto accessor = adaptor.GetPhysicsAccessor(); + auto space = accessor->GetNative().Get(); + body = CreateBody(space); + Dali::Actor ballActor = Toolkit::ImageView::New(BALL_IMAGE); + + PhysicsActor physicsActor = PhysicsActor::New(ballActor, body, adaptor); + + DALI_TEST_CHECK(physicsActor); + END_TEST; +} + +int UtcDaliPhysics2DActorDownCastP(void) +{ + ToolkitTestApplication application; + + Matrix transform(true); + Uint16Pair size(640, 480); + PhysicsAdaptor adaptor = PhysicsAdaptor::New(transform, size); + + cpBody* body{nullptr}; + auto accessor = adaptor.GetPhysicsAccessor(); + auto space = accessor->GetNative().Get(); + body = CreateBody(space); + Dali::Actor ballActor = Toolkit::ImageView::New(BALL_IMAGE); + PhysicsActor physicsActor = PhysicsActor::New(ballActor, body, adaptor); + BaseHandle handle(physicsActor); + + PhysicsActor actor2 = PhysicsActor::DownCast(handle); + DALI_TEST_CHECK(actor2); + DALI_TEST_EQUALS(physicsActor.GetId(), actor2.GetId(), TEST_LOCATION); + + END_TEST; +} + +int UtcDaliPhysics2DActorDownCastN(void) +{ + BaseHandle uninitializedHandle; + PhysicsActor actor = PhysicsActor::DownCast(uninitializedHandle); + DALI_TEST_CHECK(!actor); + END_TEST; +} + +int UtcDaliPhysics2DActorMoveConstructor(void) +{ + ToolkitTestApplication application; + tet_infoline("Testing the move constructor"); + + Matrix transform(true); + Uint16Pair size(640, 480); + PhysicsAdaptor adaptor = PhysicsAdaptor::New(transform, size); + + cpBody* body{nullptr}; + auto accessor = adaptor.GetPhysicsAccessor(); + auto space = accessor->GetNative().Get(); + body = CreateBody(space); + Dali::Actor ballActor = Toolkit::ImageView::New(BALL_IMAGE); + PhysicsActor physicsActor = PhysicsActor::New(ballActor, body, adaptor); + + DALI_TEST_CHECK(physicsActor); + uint32_t id = physicsActor.GetId(); + + PhysicsActor moved = std::move(physicsActor); + DALI_TEST_CHECK(moved); + DALI_TEST_CHECK(!physicsActor); + DALI_TEST_CHECK(moved != physicsActor); + DALI_TEST_EQUALS(moved.GetId(), id, TEST_LOCATION); + + END_TEST; +} + +int UtcDaliPhysics2DActorCopyConstructor(void) +{ + ToolkitTestApplication application; + tet_infoline("Testing the move constructor"); + + Matrix transform(true); + Uint16Pair size(640, 480); + PhysicsAdaptor adaptor = PhysicsAdaptor::New(transform, size); + + cpBody* body{nullptr}; + auto accessor = adaptor.GetPhysicsAccessor(); + auto space = accessor->GetNative().Get(); + body = CreateBody(space); + Dali::Actor ballActor = Toolkit::ImageView::New(BALL_IMAGE); + PhysicsActor physicsActor = PhysicsActor::New(ballActor, body, adaptor); + + DALI_TEST_CHECK(physicsActor); + uint32_t id = physicsActor.GetId(); + + PhysicsActor selectedActor(physicsActor); + DALI_TEST_CHECK(selectedActor); + DALI_TEST_CHECK(physicsActor); + DALI_TEST_CHECK(selectedActor == physicsActor); // should point at same object + DALI_TEST_EQUALS(selectedActor.GetId(), id, TEST_LOCATION); + + END_TEST; +} + +int UtcDaliPhysics2DActorCopyAssign(void) +{ + ToolkitTestApplication application; + tet_infoline("Testing the copy assign"); + + Matrix transform(true); + Uint16Pair size(640, 480); + PhysicsAdaptor adaptor = PhysicsAdaptor::New(transform, size); + + cpBody* body{nullptr}; + auto accessor = adaptor.GetPhysicsAccessor(); + auto space = accessor->GetNative().Get(); + body = CreateBody(space); + Dali::Actor ballActor = Toolkit::ImageView::New(BALL_IMAGE); + PhysicsActor physicsActor = PhysicsActor::New(ballActor, body, adaptor); + + DALI_TEST_CHECK(physicsActor); + uint32_t id = physicsActor.GetId(); + + PhysicsActor selectedActor = physicsActor; + DALI_TEST_CHECK(selectedActor); + DALI_TEST_CHECK(physicsActor); + DALI_TEST_CHECK(selectedActor == physicsActor); // should point at same object + DALI_TEST_EQUALS(selectedActor.GetId(), id, TEST_LOCATION); + + END_TEST; +} + +int UtcDaliPhysics2DActorMoveAssignment(void) +{ + ToolkitTestApplication application; + tet_infoline("Testing the move constructor"); + + Matrix transform(true); + Uint16Pair size(640, 480); + PhysicsAdaptor adaptor = PhysicsAdaptor::New(transform, size); + + cpBody* body{nullptr}; + auto accessor = adaptor.GetPhysicsAccessor(); + auto space = accessor->GetNative().Get(); + body = CreateBody(space); + Dali::Actor ballActor = Toolkit::ImageView::New(BALL_IMAGE); + PhysicsActor physicsActor = PhysicsActor::New(ballActor, body, adaptor); + + DALI_TEST_CHECK(physicsActor); + uint32_t id = physicsActor.GetId(); + + PhysicsActor moved; + moved = std::move(physicsActor); + DALI_TEST_CHECK(moved); + DALI_TEST_CHECK(!physicsActor); + DALI_TEST_EQUALS(moved.GetId(), id, TEST_LOCATION); + + END_TEST; +} + +int UtcDaliPhysics2DActorGetIdP(void) +{ + ToolkitTestApplication application; + tet_infoline("Testing the ID Getter"); + + Matrix transform(true); + Uint16Pair size(640, 480); + PhysicsAdaptor adaptor = PhysicsAdaptor::New(transform, size); + + cpBody* body{nullptr}; + auto accessor = adaptor.GetPhysicsAccessor(); + auto space = accessor->GetNative().Get(); + body = CreateBody(space); + Dali::Actor ballActor = Toolkit::ImageView::New(BALL_IMAGE); + PhysicsActor physicsActor = adaptor.AddActorBody(ballActor, body); + int id = physicsActor.GetId(); + int actorId = ballActor[Actor::Property::ID]; + DALI_TEST_EQUALS(id, actorId, TEST_LOCATION); + + END_TEST; +} + +int UtcDaliPhysics2DActorGetIdN(void) +{ + ToolkitTestApplication application; + tet_infoline("Testing the ID Getter"); + + PhysicsActor physicsActor; + try + { + uint32_t id __attribute__((unused)) = physicsActor.GetId(); + tet_result(TET_FAIL); + } + catch(DaliException e) + { + DALI_TEST_ASSERT(e, "Physics actor handle is empty", TEST_LOCATION); + } + + END_TEST; +} + +int UtcDaliPhysics2DActorGetBodyP(void) +{ + ToolkitTestApplication application; + tet_infoline("Testing the body Getter"); + + Matrix transform(true); + Uint16Pair size(640, 480); + PhysicsAdaptor adaptor = PhysicsAdaptor::New(transform, size); + Actor rootActor = adaptor.GetRootActor(); + auto scene = application.GetScene(); + scene.Add(rootActor); + + PhysicsActor physicsActor; + cpBody* body{nullptr}; + { + auto accessor = adaptor.GetPhysicsAccessor(); + auto space = accessor->GetNative().Get(); + body = CreateBody(space); + Dali::Actor ballActor = Toolkit::ImageView::New(BALL_IMAGE); + + physicsActor = adaptor.AddActorBody(ballActor, body); + } + + application.Render(); + Test::WaitForEventThreadTrigger(1); + + Dali::Any any = physicsActor.GetBody(); + DALI_TEST_EQUALS(any.Get(), body, TEST_LOCATION); + + END_TEST; +} + +int UtcDaliPhysics2DActorGetBodyN(void) +{ + ToolkitTestApplication application; + tet_infoline("Testing the ID Getter"); + + PhysicsActor physicsActor; + try + { + Dali::Any any __attribute__((unused)) = physicsActor.GetBody(); + tet_result(TET_FAIL); + } + catch(DaliException e) + { + DALI_TEST_ASSERT(e, "Physics actor handle is empty", TEST_LOCATION); + } + END_TEST; +} + +int UtcDaliPhysics2DActorSetPosition(void) +{ + tet_infoline("Test the AsyncSetPhysicsPosition() function"); + + ToolkitTestApplication application; + Matrix transform(false); + transform.SetIdentityAndScale(Vector3(2.0f, 2.0f, 2.0f)); + 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); + physicsActor.AsyncSetPhysicsPosition(Vector3(10, 20, -30)); + } + + Test::WaitForEventThreadTrigger(1); + adaptor.CreateSyncPoint(); + application.SendNotification(); + application.Render(); + + // Run 2 frames to ensure both buffers are set. + application.SendNotification(); + application.Render(); + { + auto accessor = adaptor.GetPhysicsAccessor(); + auto actor = rootActor.FindChildById(physicsActor.GetId()); + // Warning - physics properties are never reflected in the event size cache. + // Have to use GetCurrentProperty to see the updated values. + DALI_TEST_EQUALS(actor.GetCurrentProperty(Actor::Property::POSITION), Vector3(10, 20, 0), 0.01f, TEST_LOCATION); + } + + END_TEST; +} + +int UtcDaliPhysics2DActorSetRotation1(void) +{ + tet_infoline("Test the AsyncSetPhysicsRotation() function"); + + ToolkitTestApplication application; + Matrix transform(false); + transform.SetIdentityAndScale(Vector3(2.0f, -2.0f, 1.0f)); + 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); + physicsActor.AsyncSetPhysicsRotation(Quaternion(Degree(30), Vector3::ZAXIS)); + } + + Test::WaitForEventThreadTrigger(1); + adaptor.CreateSyncPoint(); + application.SendNotification(); + application.Render(); + + // Run 2 frames to ensure both buffers are set. + application.SendNotification(); + application.Render(); + { + auto accessor = adaptor.GetPhysicsAccessor(); + auto actor = rootActor.FindChildById(physicsActor.GetId()); + // Warning - physics properties are never reflected in the event size cache. + // Have to use GetCurrentProperty to see the updated values. + Quaternion q = actor.GetCurrentProperty(Actor::Property::ORIENTATION); + Quaternion expected(Degree(30), Vector3::ZAXIS); + DALI_TEST_EQUALS(q, expected, 0.0001f, TEST_LOCATION); + } + + END_TEST; +} + +int UtcDaliPhysics2DActorSetRotation2(void) +{ + tet_infoline("Test the AsyncSetPhysicsRotation() function"); + + ToolkitTestApplication application; + Matrix transform(false); + transform.SetIdentityAndScale(Vector3(2.0f, -2.0f, 1.0f)); + 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); + physicsActor.AsyncSetPhysicsRotation(Quaternion(Degree(30), Vector3::ZAXIS)); + } + + Test::WaitForEventThreadTrigger(1); + adaptor.CreateSyncPoint(); + application.SendNotification(); + application.Render(); + + // Run 2 frames to ensure both buffers are set. + application.SendNotification(); + application.Render(); + { + auto accessor = adaptor.GetPhysicsAccessor(); + auto actor = rootActor.FindChildById(physicsActor.GetId()); + // Warning - physics properties are never reflected in the event size cache. + // Have to use GetCurrentProperty to see the updated values. + Quaternion q = actor.GetCurrentProperty(Actor::Property::ORIENTATION); + Quaternion expected(Degree(30), Vector3::ZAXIS); + DALI_TEST_EQUALS(q, expected, 0.001f, TEST_LOCATION); + } + + END_TEST; +} + +int UtcDaliPhysics2DActorGetActorPosition(void) +{ + tet_infoline("Test the GetActorPosition() function"); + + ToolkitTestApplication application; + Matrix transform(false); + transform.SetIdentityAndScale(Vector3(2.0f, 2.0f, 2.0f)); + 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); + tet_infoline("Test that Z is ignored"); + physicsActor.AsyncSetPhysicsPosition(Vector3(10, 20, -30)); + } + + Test::WaitForEventThreadTrigger(1); + adaptor.CreateSyncPoint(); + application.SendNotification(); + application.Render(); + + // Run 2 frames to ensure both buffers are set. + application.SendNotification(); + application.Render(); + { + auto accessor = adaptor.GetPhysicsAccessor(); + tet_infoline("Test that Z is ignored. Note, error is quite high, so make epsilon low"); + DALI_TEST_EQUALS(physicsActor.GetActorPosition(), Vector3(10, 20, 0), 0.01f, TEST_LOCATION); + } + + END_TEST; +} + +int UtcDaliPhysics2DActorGetActorRotation(void) +{ + tet_infoline("Test the GetActorRotation() function"); + + ToolkitTestApplication application; + Matrix transform(false); + transform.SetIdentityAndScale(Vector3(2.0f, 2.0f, 2.0f)); + 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); + physicsActor.AsyncSetPhysicsRotation(Quaternion(Degree(30), Vector3::ZAXIS)); + } + + Test::WaitForEventThreadTrigger(1); + adaptor.CreateSyncPoint(); + application.SendNotification(); + application.Render(); + + // Run 2 frames to ensure both buffers are set. + application.SendNotification(); + application.Render(); + { + auto accessor = adaptor.GetPhysicsAccessor(); + DALI_TEST_EQUALS(physicsActor.GetActorRotation(), Quaternion(Degree(30), Vector3::ZAXIS), 0.0001f, TEST_LOCATION); + } + + END_TEST; +} + +int UtcDaliPhysics2DActorGetPhysicsPosition(void) +{ + tet_infoline("Test the GetPhysicsPosition() function"); + + ToolkitTestApplication application; + Matrix transform(false); + transform.SetIdentityAndScale(Vector3(2.0f, 2.0f, 2.0f)); + + 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); + physicsActor.AsyncSetPhysicsPosition(Vector3(10, 20, -30)); + } + + Test::WaitForEventThreadTrigger(1); + adaptor.CreateSyncPoint(); + application.SendNotification(); + application.Render(); + + // Run 2 frames to ensure both buffers are set. + application.SendNotification(); + application.Render(); + { + auto accessor = adaptor.GetPhysicsAccessor(); + Vector4 pos = transform * Vector4(10, 20, 0, 1); + DALI_TEST_EQUALS(physicsActor.GetPhysicsPosition(), Vector3(pos), 0.01f, TEST_LOCATION); + } + + END_TEST; +} + +int UtcDaliPhysics2DActorGetPhysicsRotation(void) +{ + tet_infoline("Test the GetPhysicsRotation() function"); + + ToolkitTestApplication application; + Matrix transform(false); + transform.SetIdentityAndScale(Vector3(2.0f, -2.0f, 1.0f)); + 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); + physicsActor.AsyncSetPhysicsRotation(Quaternion(Degree(30), Vector3::ZAXIS)); + } + + Test::WaitForEventThreadTrigger(1); + adaptor.CreateSyncPoint(); + application.SendNotification(); + application.Render(); + + // Run 2 frames to ensure both buffers are set. + application.SendNotification(); + application.Render(); + { + tet_infoline("Check that actor and physics rotations are identical"); + auto accessor = adaptor.GetPhysicsAccessor(); + DALI_TEST_EQUALS(physicsActor.GetPhysicsRotation(), Quaternion(Degree(30), Vector3::ZAXIS), 0.0001f, TEST_LOCATION); + } + + END_TEST; +} diff --git a/automated-tests/src/dali-physics2d/utc-Dali-PhysicsAdaptor.cpp b/automated-tests/src/dali-physics2d/utc-Dali-PhysicsAdaptor.cpp new file mode 100644 index 0000000..b6ca868 --- /dev/null +++ b/automated-tests/src/dali-physics2d/utc-Dali-PhysicsAdaptor.cpp @@ -0,0 +1,935 @@ +/* + * 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 + +using namespace Dali; +using namespace Dali::Toolkit::Physics; + +void utc_dali_physics2d_startup(void) +{ + test_return_value = TET_UNDEF; +} + +void utc_dali_physics2d_cleanup(void) +{ + test_return_value = TET_PASS; +} + +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; +} + +int UtcDaliPhysics2DCreateAdaptorP1(void) +{ + ToolkitTestApplication application; + + Matrix transform(true); + Uint16Pair size(640, 480); + + PhysicsAdaptor handle = PhysicsAdaptor::New(transform, size); + DALI_TEST_CHECK(handle); + + END_TEST; +} + +int UtcDaliPhysics2DCreateAdaptorN1(void) +{ + ToolkitTestApplication application; + + PhysicsAdaptor handle; + DALI_TEST_CHECK(!handle); + + END_TEST; +} + +int UtcDaliPhysics2DDowncastP1(void) +{ + ToolkitTestApplication application; + + Matrix transform(true); + Uint16Pair size(640, 480); + + BaseHandle handle = PhysicsAdaptor::New(transform, size); + + auto adaptor = PhysicsAdaptor::DownCast(handle); + DALI_TEST_CHECK(adaptor); + //Following only works if type is registered + //DALI_TEST_EQUALS("PhysicsAdaptor", adaptor.GetTypeName(), TEST_LOCATION); + END_TEST; +} + +int UtcDaliPhysics2DDowncastN1(void) +{ + BaseHandle handle; + auto adaptor = PhysicsAdaptor::DownCast(handle); + DALI_TEST_CHECK(!adaptor); + + DALI_TEST_CHECK(typeid(PhysicsAdaptor) == typeid(decltype(adaptor))); + END_TEST; +} + +int UtcDaliPhysics2DAdaptorMoveConstructor(void) +{ + ToolkitTestApplication application; + tet_infoline("Testing the move constructor"); + + Matrix transform(true); + Uint16Pair size(640, 480); + PhysicsAdaptor adaptor = PhysicsAdaptor::New(transform, size); + DALI_TEST_CHECK(adaptor); + + PhysicsAdaptor moved = std::move(adaptor); + DALI_TEST_CHECK(moved); + DALI_TEST_CHECK(!adaptor); + DALI_TEST_CHECK(moved != adaptor); + + END_TEST; +} + +int UtcDaliPhysics2DAdaptorCopyConstructor(void) +{ + ToolkitTestApplication application; + tet_infoline("Testing the move constructor"); + + Matrix transform(true); + Uint16Pair size(640, 480); + PhysicsAdaptor adaptor = PhysicsAdaptor::New(transform, size); + + DALI_TEST_CHECK(adaptor); + + PhysicsAdaptor altAdaptor = adaptor; + DALI_TEST_CHECK(altAdaptor); + DALI_TEST_CHECK(adaptor); + DALI_TEST_CHECK(altAdaptor == adaptor); // should point at same object + + END_TEST; +} + +int UtcDaliPhysics2DAdaptorCopyAssign(void) +{ + ToolkitTestApplication application; + tet_infoline("Testing the copy assign"); + + Matrix transform(true); + Uint16Pair size(640, 480); + PhysicsAdaptor adaptor = PhysicsAdaptor::New(transform, size); + DALI_TEST_CHECK(adaptor); + + PhysicsAdaptor altAdaptor = adaptor; + DALI_TEST_CHECK(altAdaptor); + DALI_TEST_CHECK(adaptor); + DALI_TEST_CHECK(altAdaptor == adaptor); // should point at same object + + END_TEST; +} + +int UtcDaliPhysics2DAdaptorMoveAssignment(void) +{ + ToolkitTestApplication application; + tet_infoline("Testing the move constructor"); + + Matrix transform(true); + Uint16Pair size(640, 480); + PhysicsAdaptor adaptor = PhysicsAdaptor::New(transform, size); + DALI_TEST_CHECK(adaptor); + + PhysicsAdaptor moved; + moved = std::move(adaptor); + DALI_TEST_CHECK(moved); + DALI_TEST_CHECK(!adaptor); + + END_TEST; +} + +int UtcDaliPhysics2DSetTimestep(void) +{ + ToolkitTestApplication application; + + Matrix transform(true); + Uint16Pair size(640, 480); + + PhysicsAdaptor adaptor = PhysicsAdaptor::New(transform, size); + adaptor.SetTimestep(1.0f / 60.0f); + + DALI_TEST_EQUALS(adaptor.GetTimestep(), 1.0f / 60.0f, 0.0001f, TEST_LOCATION); + + END_TEST; +} + +int UtcDaliPhysics2DGetTimestep(void) +{ + ToolkitTestApplication application; + + Matrix transform(true); + Uint16Pair size(640, 480); + + PhysicsAdaptor adaptor = PhysicsAdaptor::New(transform, size); + adaptor.SetTimestep(1.0f / 60.0f); + float timestep = adaptor.GetTimestep(); + float expected = 1.0f / 60.0f; + DALI_TEST_EQUALS(timestep, expected, 0.0001f, TEST_LOCATION); + + adaptor.SetTimestep(1.0f / 120.0f); + timestep = adaptor.GetTimestep(); + expected = 1.0f / 120.0f; + DALI_TEST_EQUALS(timestep, expected, 0.0001f, TEST_LOCATION); + + END_TEST; +} + +int UtcDaliPhysics2DGetPhysicsAccessorP1(void) +{ + ToolkitTestApplication application; + + Matrix transform(true); + Uint16Pair size(640, 480); + + PhysicsAdaptor adaptor = PhysicsAdaptor::New(transform, size); + PhysicsAdaptor::ScopedPhysicsAccessorPtr accessor = adaptor.GetPhysicsAccessor(); + DALI_TEST_CHECK(accessor.get() != nullptr); + + Dali::Any world = accessor->GetNative(); + DALI_TEST_CHECK(!world.Empty()); + + END_TEST; +} + +int UtcDaliPhysics2DGetPhysicsAccessorN1(void) +{ + ToolkitTestApplication application; + + PhysicsAdaptor handle; + DALI_TEST_CHECK(!handle); + + try + { + auto ptr = handle.GetPhysicsAccessor(); + DALI_TEST_CHECK(ptr == nullptr); + + tet_result(TET_FAIL); + } + catch(DaliException& e) + { + DALI_TEST_ASSERT(e, "Physics adaptor handle is empty", TEST_LOCATION); + } + + END_TEST; +} + +int UtcDaliPhysics2DAdaptorGetRootActor(void) +{ + tet_infoline("Test that the root actor can be retrieved"); + + ToolkitTestApplication application; + Matrix transform(false); + transform.SetIdentityAndScale(Vector3(2.0f, 2.0f, 1.0f)); + Uint16Pair size(640, 480); + auto scene = application.GetScene(); + PhysicsAdaptor adaptor = PhysicsAdaptor::New(transform, size); + Actor rootActor = adaptor.GetRootActor(); + scene.Add(rootActor); + + DALI_TEST_CHECK(rootActor); + DALI_TEST_EQUALS(rootActor.GetProperty(Actor::Property::SIZE), Vector2(640.0f, 480.0f), 0.001f, TEST_LOCATION); + + END_TEST; +} + +int UtcDaliPhysics2DAdaptorCreateDebugLayer(void) +{ + ToolkitTestApplication application; + Matrix transform(true); + transform.SetIdentityAndScale(Vector3(2.0f, 2.0f, 1.0f)); + Uint16Pair size(640, 480); + auto scene = application.GetScene(); + + PhysicsAdaptor adaptor = PhysicsAdaptor::New(transform, size); + Actor rootActor = adaptor.GetRootActor(); + scene.Add(rootActor); + Window window = DevelWindow::Get(rootActor); + + Layer layer = adaptor.CreateDebugLayer(window); + DALI_TEST_CHECK(!layer); + + END_TEST; +} + +int UtcDaliPhysics2DAdaptorTranslateToPhysicsSpace1(void) +{ + ToolkitTestApplication application; + Matrix transform(false); + transform.SetIdentityAndScale(Vector3(2.0f, 2.0f, 1.0f)); + Uint16Pair size(640, 480); + PhysicsAdaptor adaptor = PhysicsAdaptor::New(transform, size); + + Vector3 a(30, 20, 10); + Vector3 expected(60, 40, 10); + DALI_TEST_EQUALS(adaptor.TranslateToPhysicsSpace(a), expected, 0.0001f, TEST_LOCATION); + + END_TEST; +} + +int UtcDaliPhysics2DAdaptorTranslateToPhysicsSpace2(void) +{ + ToolkitTestApplication application; + Matrix transform(false); + tet_infoline("Test that using an alternative scale doesn't change rotation"); + transform.SetIdentityAndScale(Vector3(2.0f, 2.0f, 1.0f)); + Uint16Pair size(640, 480); + PhysicsAdaptor adaptor = PhysicsAdaptor::New(transform, size); + + // Rotation shouldn't change under this scale + Quaternion q(Degree(30.0f), Vector3::XAXIS); + DALI_TEST_EQUALS(adaptor.TranslateToPhysicsSpace(q), q, 0.0001f, TEST_LOCATION); + + END_TEST; +} + +int UtcDaliPhysics2DAdaptorTranslateToPhysicsSpace3(void) +{ + ToolkitTestApplication application; + Matrix transform(false); + tet_infoline("Test that using an inverted Y scale does nothing to rotation"); + + transform.SetIdentityAndScale(Vector3(1.0f, -1.0f, 1.0f)); + Uint16Pair size(640, 480); + PhysicsAdaptor adaptor = PhysicsAdaptor::New(transform, size); + + Quaternion q(Degree(30.0f), Vector3::ZAXIS); + Quaternion qp(Degree(30.0f), Vector3::ZAXIS); + + DALI_TEST_EQUALS(adaptor.TranslateToPhysicsSpace(q), qp, 0.0001f, TEST_LOCATION); + + END_TEST; +} + +int UtcDaliPhysics2DAdaptorTranslateToPhysicsSpace4(void) +{ + ToolkitTestApplication application; + Matrix transform(false); + tet_infoline("Test that using an inverted Y scale does nothing to rotation"); + + transform.SetIdentityAndScale(Vector3(1.0f, -1.0f, 1.0f)); + Uint16Pair size(640, 480); + PhysicsAdaptor adaptor = PhysicsAdaptor::New(transform, size); + + Quaternion q(Degree(30.0f), Vector3::XAXIS); + Quaternion qp(Degree(30.0f), Vector3::XAXIS); + + DALI_TEST_EQUALS(adaptor.TranslateToPhysicsSpace(q), qp, 0.0001f, TEST_LOCATION); + + END_TEST; +} + +int UtcDaliPhysics2DAdaptorTranslateToPhysicsSpace5(void) +{ + ToolkitTestApplication application; + Matrix transform(false); + tet_infoline("Test that using an inverted Y scale does nothing to rotation"); + + transform.SetIdentityAndScale(Vector3(1.0f, -1.0f, 1.0f)); + Uint16Pair size(640, 480); + PhysicsAdaptor adaptor = PhysicsAdaptor::New(transform, size); + + Quaternion q(Degree(30.0f), Vector3::YAXIS); + Quaternion qp(Degree(30.0f), Vector3::YAXIS); + + DALI_TEST_EQUALS(adaptor.TranslateToPhysicsSpace(q), qp, 0.0001f, TEST_LOCATION); + + END_TEST; +} + +int UtcDaliPhysics2DAdaptorTranslateFromPhysicsSpace1(void) +{ + ToolkitTestApplication application; + Matrix transform(false); + tet_infoline("Test that using a double scale halves position"); + + transform.SetIdentityAndScale(Vector3(2.0f, -2.0f, 1.0f)); + Uint16Pair size(640, 480); + PhysicsAdaptor adaptor = PhysicsAdaptor::New(transform, size); + + Vector3 position(20.0f, 20.0f, 0.0f); + Vector3 expected(10.0f, -10.0f, 0.0f); + + DALI_TEST_EQUALS(adaptor.TranslateFromPhysicsSpace(position), expected, 0.0001f, TEST_LOCATION); + + END_TEST; +} + +int UtcDaliPhysics2DAdaptorConvertVectorToPhysicsSpace01(void) +{ + ToolkitTestApplication application; + Matrix transform(false); + tet_infoline("Test that using a translation does not translate vector"); + + transform.SetIdentityAndScale(Vector3(1.0f, 1.0f, 1.0f)); + transform.SetTranslation(Vector3(0.0f, 100.0f, 0.0f)); + Uint16Pair size(640, 480); + PhysicsAdaptor adaptor = PhysicsAdaptor::New(transform, size); + Vector3 vector(20.0f, 20.0f, 0.0f); + DALI_TEST_EQUALS(adaptor.ConvertVectorToPhysicsSpace(vector), vector, 0.0001f, TEST_LOCATION); + + END_TEST; +} + +int UtcDaliPhysics2DAdaptorConvertVectorToPhysicsSpace02(void) +{ + ToolkitTestApplication application; + Matrix transform(false); + tet_infoline("Test that using a translation with inverse Y does not translate vector"); + + transform.SetIdentityAndScale(Vector3(1.0f, -1.0f, 1.0f)); + transform.SetTranslation(Vector3(0.0f, 100.0f, 0.0f)); + Uint16Pair size(640, 480); + PhysicsAdaptor adaptor = PhysicsAdaptor::New(transform, size); + Vector3 vector(20.0f, 20.0f, 0.0f); + Vector3 expected(20.0f, -20.0f, 0.0f); + DALI_TEST_EQUALS(adaptor.ConvertVectorToPhysicsSpace(vector), expected, 0.0001f, TEST_LOCATION); + + END_TEST; +} + +int UtcDaliPhysics2DAdaptorConvertVectorFromPhysicsSpace01(void) +{ + ToolkitTestApplication application; + Matrix transform(false); + tet_infoline("Test that using a translation does not translate vector"); + + transform.SetIdentityAndScale(Vector3(1.0f, 1.0f, 1.0f)); + transform.SetTranslation(Vector3(0.0f, 100.0f, 0.0f)); + Uint16Pair size(640, 480); + PhysicsAdaptor adaptor = PhysicsAdaptor::New(transform, size); + Vector3 vector(20.0f, 20.0f, 0.0f); + DALI_TEST_EQUALS(adaptor.ConvertVectorFromPhysicsSpace(vector), vector, 0.0001f, TEST_LOCATION); + + END_TEST; +} + +int UtcDaliPhysics2DAdaptorConvertVectorFromPhysicsSpace02(void) +{ + ToolkitTestApplication application; + Matrix transform(false); + tet_infoline("Test that using a translation with inverse Y does not translate vector"); + + transform.SetIdentityAndScale(Vector3(1.0f, -1.0f, 1.0f)); + transform.SetTranslation(Vector3(0.0f, 100.0f, 0.0f)); + Uint16Pair size(640, 480); + PhysicsAdaptor adaptor = PhysicsAdaptor::New(transform, size); + Vector3 vector(20.0f, 20.0f, 0.0f); + Vector3 expected(20.0f, -20.0f, 0.0f); + DALI_TEST_EQUALS(adaptor.ConvertVectorFromPhysicsSpace(vector), expected, 0.0001f, TEST_LOCATION); + + END_TEST; +} + +int UtcDaliPhysics2DAdaptorSetTransformAndSize(void) +{ + ToolkitTestApplication application; + Matrix transform(false); + transform.SetIdentityAndScale(Vector3(2.0f, 2.0f, 1.0f)); + Uint16Pair size(640, 480); + PhysicsAdaptor adaptor = PhysicsAdaptor::New(transform, size); + + Vector3 a(30, 20, 10); + Vector3 expected(60, 40, 10); + DALI_TEST_EQUALS(adaptor.TranslateToPhysicsSpace(a), expected, 0.0001f, TEST_LOCATION); + + transform.SetIdentityAndScale(Vector3(1.0f, -1.0f, 1.0f)); + transform.SetTranslation(Vector3(0.0f, 100.0f, 0.0f)); + adaptor.SetTransformAndSize(transform, size); + + Vector3 expect2(30, 80, 10); + DALI_TEST_EQUALS(adaptor.TranslateToPhysicsSpace(a), expect2, 0.0001f, TEST_LOCATION); + + END_TEST; +} + +int UtcDaliPhysics2DAdaptorSetIntegrationState(void) +{ + tet_infoline("Test that changing the integration state is reflected"); + + ToolkitTestApplication application; + Matrix transform(false); + transform.SetIdentityAndScale(Vector3(2.0f, 2.0f, 1.0f)); + Uint16Pair size(640, 480); + auto scene = application.GetScene(); + PhysicsAdaptor adaptor = PhysicsAdaptor::New(transform, size); + Actor rootActor = adaptor.GetRootActor(); + scene.Add(rootActor); + + DALI_TEST_CHECK(adaptor.GetIntegrationState() == PhysicsAdaptor::IntegrationState::ON); + + adaptor.SetIntegrationState(PhysicsAdaptor::IntegrationState::OFF); + DALI_TEST_CHECK(adaptor.GetIntegrationState() == PhysicsAdaptor::IntegrationState::OFF); + + END_TEST; +} + +int UtcDaliPhysics2DAdaptorGetIntegrationState(void) +{ + tet_infoline("Test that changing the integration state is reflected"); + + ToolkitTestApplication application; + Matrix transform(false); + transform.SetIdentityAndScale(Vector3(2.0f, 2.0f, 1.0f)); + Uint16Pair size(640, 480); + auto scene = application.GetScene(); + PhysicsAdaptor adaptor = PhysicsAdaptor::New(transform, size); + Actor rootActor = adaptor.GetRootActor(); + scene.Add(rootActor); + + adaptor.SetIntegrationState(PhysicsAdaptor::IntegrationState::OFF); + DALI_TEST_CHECK(adaptor.GetIntegrationState() == PhysicsAdaptor::IntegrationState::OFF); + + adaptor.SetIntegrationState(PhysicsAdaptor::IntegrationState::ON); + DALI_TEST_CHECK(adaptor.GetIntegrationState() == PhysicsAdaptor::IntegrationState::ON); + + // Can't test actual integration step runs without adding actors - see utc-Dali-PhysicsActor.cpp. + END_TEST; +} + +int UtcDaliPhysics2DAdaptorSetDebugState(void) +{ + tet_infoline("Test that changing the debug state is reflected"); + + ToolkitTestApplication application; + Matrix transform(false); + transform.SetIdentityAndScale(Vector3(2.0f, 2.0f, 1.0f)); + Uint16Pair size(640, 480); + auto scene = application.GetScene(); + PhysicsAdaptor adaptor = PhysicsAdaptor::New(transform, size); + Actor rootActor = adaptor.GetRootActor(); + scene.Add(rootActor); + + DALI_TEST_CHECK(adaptor.GetDebugState() == PhysicsAdaptor::DebugState::OFF); + + adaptor.SetDebugState(PhysicsAdaptor::DebugState::ON); + DALI_TEST_CHECK(adaptor.GetDebugState() == PhysicsAdaptor::DebugState::ON); + + adaptor.SetDebugState(PhysicsAdaptor::DebugState::OFF); + DALI_TEST_CHECK(adaptor.GetDebugState() == PhysicsAdaptor::DebugState::OFF); + + END_TEST; +} + +int UtcDaliPhysics2DAdaptorGetDebugState(void) +{ + tet_infoline("Test that changing the debug state is reflected"); + + ToolkitTestApplication application; + Matrix transform(false); + transform.SetIdentityAndScale(Vector3(2.0f, 2.0f, 1.0f)); + Uint16Pair size(640, 480); + auto scene = application.GetScene(); + PhysicsAdaptor adaptor = PhysicsAdaptor::New(transform, size); + Actor rootActor = adaptor.GetRootActor(); + scene.Add(rootActor); + + adaptor.SetDebugState(PhysicsAdaptor::DebugState::OFF); + DALI_TEST_CHECK(adaptor.GetDebugState() == PhysicsAdaptor::DebugState::OFF); + + adaptor.SetDebugState(PhysicsAdaptor::DebugState::ON); + DALI_TEST_CHECK(adaptor.GetDebugState() == PhysicsAdaptor::DebugState::ON); + + // Can't test actual debug step runs without adding actors - see utc-Dali-PhysicsActor.cpp. + END_TEST; +} + +int UtcDaliPhysics2DAdaptorAddActorBody(void) +{ + tet_infoline("Test that an actor/body pair can be added"); + + ToolkitTestApplication application; + Matrix transform(false); + transform.SetIdentityAndScale(Vector3(2.0f, 2.0f, 1.0f)); + Uint16Pair size(640, 480); + auto scene = application.GetScene(); + PhysicsAdaptor adaptor = PhysicsAdaptor::New(transform, size); + Actor rootActor = adaptor.GetRootActor(); + scene.Add(rootActor); + + auto accessor = adaptor.GetPhysicsAccessor(); + auto space = accessor->GetNative().Get(); + + cpBody* body = CreateBody(space); + Dali::Actor ballActor = Toolkit::ImageView::New("gallery-small-1.jpg"); + auto physicsActor = adaptor.AddActorBody(ballActor, body); + + DALI_TEST_CHECK(physicsActor); + int id = ballActor[Actor::Property::ID]; + + DALI_TEST_EQUALS(physicsActor.GetId(), id, TEST_LOCATION); + DALI_TEST_EQUALS(physicsActor.GetBody().Get(), body, TEST_LOCATION); + + END_TEST; +} + +void removeShape(cpBody* body, cpShape* shape, void* data) +{ + cpSpace* space = static_cast(data); + cpSpaceRemoveShape(space, shape); + cpShapeSetBody(shape, nullptr); + cpShapeFree(shape); +} + +int UtcDaliPhysics2DAdaptorRemoveActorBodyP01(void) +{ + tet_infoline("Test that an actor/body pair can be removed"); + + ToolkitTestApplication application; + Matrix transform(false); + transform.SetIdentityAndScale(Vector3(2.0f, 2.0f, 2.0f)); + Uint16Pair size(640, 480); + auto scene = application.GetScene(); + PhysicsAdaptor adaptor = PhysicsAdaptor::New(transform, size); + Actor rootActor = adaptor.GetRootActor(); + scene.Add(rootActor); + + cpBody* body; + { + auto accessor = adaptor.GetPhysicsAccessor(); + auto space = accessor->GetNative().Get(); + + body = CreateBody(space); + } + Dali::Actor ballActor = Toolkit::ImageView::New("gallery-small-1.jpg"); + auto physicsActor = adaptor.AddActorBody(ballActor, body); + + application.SendNotification(); + application.Render(); + application.SendNotification(); + application.Render(); + + adaptor.RemoveActorBody(physicsActor); + DALI_TEST_CHECK(!ballActor.GetParent()); + + { + auto accessor = adaptor.GetPhysicsAccessor(); + auto space = accessor->GetNative().Get(); + + try + { + cpBodyEachShape(body, removeShape, space); + cpSpaceRemoveBody(space, body); + tet_result(TET_PASS); + } + catch(std::exception& e) + { + tet_result(TET_FAIL); + } + } + + END_TEST; +} + +int UtcDaliPhysics2DAdaptorRemoveActorBodyN01(void) +{ + ToolkitTestApplication application; + Matrix transform(false); + transform.SetIdentityAndScale(Vector3(2.0f, 2.0f, 2.0f)); + Uint16Pair size(640, 480); + auto scene = application.GetScene(); + PhysicsAdaptor adaptor = PhysicsAdaptor::New(transform, size); + Actor rootActor = adaptor.GetRootActor(); + scene.Add(rootActor); + + tet_infoline("Test that removing a physics actor that hasn't been created with AddActorBody does nothing"); + Dali::Actor actor = Dali::Actor::New(); + cpBody* body = cpBodyNew(1.0f, 1.0f); + PhysicsActor physicsActor = PhysicsActor::New(actor, body, adaptor); + ; + try + { + adaptor.RemoveActorBody(physicsActor); + tet_result(TET_PASS); + } + catch(std::exception& e) + { + // Should fail silently, without exception! + tet_result(TET_FAIL); + } + + END_TEST; +} + +int UtcDaliPhysics2DAdaptorRemoveActorBodyN02(void) +{ + tet_infoline("Test that an empty actor/body pair doesn't break adaptor"); + + ToolkitTestApplication application; + Matrix transform(false); + transform.SetIdentityAndScale(Vector3(2.0f, 2.0f, 2.0f)); + Uint16Pair size(640, 480); + auto scene = application.GetScene(); + PhysicsAdaptor adaptor = PhysicsAdaptor::New(transform, size); + Actor rootActor = adaptor.GetRootActor(); + scene.Add(rootActor); + + PhysicsActor physicsActor; + try + { + adaptor.RemoveActorBody(physicsActor); + tet_result(TET_FAIL); + } + catch(DaliException& e) + { + DALI_TEST_ASSERT(e, "Physics actor handle is empty", TEST_LOCATION); + } + + END_TEST; +} + +int UtcDaliPhysics2DAdaptorGetPhysicsActor(void) +{ + tet_infoline("Test that an actor/body pair can be retrieved"); + + ToolkitTestApplication application; + Matrix transform(false); + transform.SetIdentityAndScale(Vector3(2.0f, 2.0f, 1.0f)); + Uint16Pair size(640, 480); + auto scene = application.GetScene(); + PhysicsAdaptor adaptor = PhysicsAdaptor::New(transform, size); + Actor rootActor = adaptor.GetRootActor(); + scene.Add(rootActor); + + auto accessor = adaptor.GetPhysicsAccessor(); + auto space = accessor->GetNative().Get(); + + cpBody* body = CreateBody(space); + Dali::Actor ballActor = Toolkit::ImageView::New("gallery-small-1.jpg"); + auto physicsActor = adaptor.AddActorBody(ballActor, body); + + DALI_TEST_CHECK(physicsActor); + + PhysicsActor testActor = adaptor.GetPhysicsActor(body); + DALI_TEST_CHECK(testActor); + DALI_TEST_CHECK(physicsActor == testActor); + + END_TEST; +} + +int UtcDaliPhysics2DAdaptorBuildPickingRay(void) +{ + tet_infoline("Test that picking ray converts screen coords"); + + ToolkitTestApplication application; + Matrix transform(false); + transform.SetIdentityAndScale(Vector3(1.0f, 1.0f, 1.0f)); + Uint16Pair size(TestApplication::DEFAULT_SURFACE_WIDTH, TestApplication::DEFAULT_SURFACE_HEIGHT); + const Vector2 center(TestApplication::DEFAULT_SURFACE_WIDTH * 0.5f, TestApplication::DEFAULT_SURFACE_HEIGHT * 0.5f); + PhysicsAdaptor adaptor = PhysicsAdaptor::New(transform, size); + Actor rootActor = adaptor.GetRootActor(); + auto scene = application.GetScene(); + scene.Add(rootActor); + + Vector3 from, to; + adaptor.BuildPickingRay(Vector3(center), Vector3(center), from, to); // Hit test centre of screen + Vector3 physCenter = adaptor.TranslateToPhysicsSpace(Vector3(center)); + DALI_TEST_EQUALS(from, physCenter, 0.001f, TEST_LOCATION); + + END_TEST; +} + +int UtcDaliPhysics2DAdaptorProjectPoint(void) +{ + tet_infoline("Test that a point is projected into physics space"); + + ToolkitTestApplication application; + Matrix transform(false); + transform.SetIdentityAndScale(Vector3(2.0f, 2.0f, 1.0f)); + Uint16Pair size(640, 480); + PhysicsAdaptor adaptor = PhysicsAdaptor::New(transform, size); + + Vector3 projectedPoint = adaptor.ProjectPoint(Vector3(), -Vector3::ZAXIS, 200); + + DALI_TEST_EQUALS(projectedPoint, Vector3(0.0f, 0.0f, 0.0f), 0.001f, TEST_LOCATION); + + END_TEST; +} + +int UtcDaliPhysics2DAdaptorQueue(void) +{ + tet_infoline("Test that Queue and CreateSyncPoint both work"); + + ToolkitTestApplication application; + Matrix transform(false); + transform.SetIdentityAndScale(Vector3(2.0f, 2.0f, 1.0f)); + Uint16Pair size(640, 480); + PhysicsAdaptor adaptor = PhysicsAdaptor::New(transform, size); + Actor rootActor = adaptor.GetRootActor(); + auto scene = application.GetScene(); + scene.Add(rootActor); + + cpBody* body{nullptr}; + { + auto accessor = adaptor.GetPhysicsAccessor(); + auto space = accessor->GetNative().Get(); + body = CreateBody(space); + Dali::Actor ballActor = Toolkit::ImageView::New("gallery-small-1.jpg"); + auto physicsActor = adaptor.AddActorBody(ballActor, body); + } + + tet_infoline("Test that Queue works without accessor"); + adaptor.Queue([body]() { + cpBodySetPosition(body, cpv(100.0f, 20.0f)); + }); + adaptor.CreateSyncPoint(); + + application.SendNotification(); + application.Render(); + // Should trigger an Update + + { + auto accessor = adaptor.GetPhysicsAccessor(); + cpVect origin = cpBodyGetPosition(body); + + DALI_TEST_EQUALS(origin.x, cpFloat(100.0f), 0.001f, TEST_LOCATION); + DALI_TEST_EQUALS(origin.y, cpFloat(20.0f), 0.001f, TEST_LOCATION); + } + + END_TEST; +} + +int UtcDaliPhysics2DAdaptorCreateSyncPoint(void) +{ + tet_infoline("Test that a delayed CreateSyncPoint delays update"); + + ToolkitTestApplication application; + Matrix transform(false); + transform.SetIdentityAndScale(Vector3(2.0f, 2.0f, 1.0f)); + Uint16Pair size(640, 480); + PhysicsAdaptor adaptor = PhysicsAdaptor::New(transform, size); + Actor rootActor = adaptor.GetRootActor(); + auto scene = application.GetScene(); + scene.Add(rootActor); + + cpBody* body{nullptr}; + { + auto accessor = adaptor.GetPhysicsAccessor(); + auto space = accessor->GetNative().Get(); + body = CreateBody(space); + Dali::Actor ballActor = Toolkit::ImageView::New("gallery-small-1.jpg"); + auto physicsActor = adaptor.AddActorBody(ballActor, body); + + tet_infoline("Test that Queue works with accessor"); + adaptor.Queue([body]() { + cpBodySetPosition(body, cpv(100.0f, 20.0f)); + }); + } + + // Should trigger an Update without processing queue + application.SendNotification(); + application.Render(); + + { + auto accessor = adaptor.GetPhysicsAccessor(); + + cpVect origin = cpBodyGetPosition(body); + DALI_TEST_EQUALS(origin.x, cpFloat(0.0f), 0.01f, TEST_LOCATION); + DALI_TEST_EQUALS(origin.y, cpFloat(0.0f), 0.01f, TEST_LOCATION); + } + + // Should now execute queue + adaptor.CreateSyncPoint(); + application.SendNotification(); + application.Render(); + + { + auto accessor = adaptor.GetPhysicsAccessor(); + + cpVect origin = cpBodyGetPosition(body); + DALI_TEST_EQUALS(origin.x, cpFloat(100.0f), 0.01f, TEST_LOCATION); + DALI_TEST_EQUALS(origin.y, cpFloat(20.0f), 0.01f, TEST_LOCATION); + } + + END_TEST; +} + +int UtcDaliPhysics2DAdaptorHitTestP(void) +{ + tet_infoline("Test that hit testing finds a body"); + + ToolkitTestApplication application; + Matrix transform(false); + transform.SetIdentityAndScale(Vector3(1.0f, 1.0f, 1.0f)); + Uint16Pair size(TestApplication::DEFAULT_SURFACE_WIDTH, TestApplication::DEFAULT_SURFACE_HEIGHT); + const Vector2 center(TestApplication::DEFAULT_SURFACE_WIDTH * 0.5f, TestApplication::DEFAULT_SURFACE_HEIGHT * 0.5f); + PhysicsAdaptor adaptor = PhysicsAdaptor::New(transform, size); + Actor rootActor = adaptor.GetRootActor(); + auto scene = application.GetScene(); + scene.Add(rootActor); + + { + auto accessor = adaptor.GetPhysicsAccessor(); // Prevent integration + auto space = accessor->GetNative().Get(); + Dali::Actor ballActor = Toolkit::ImageView::New(TEST_RESOURCE_DIR "/gallery-small-1.jpg"); + cpBody* body = CreateBody(space); + cpBodySetPosition(body, cpv(center.x, center.y)); + + ballActor[Actor::Property::PARENT_ORIGIN] = ParentOrigin::CENTER; + ballActor[Actor::Property::ANCHOR_POINT] = AnchorPoint::CENTER; + + auto physicsActor = adaptor.AddActorBody(ballActor, body); + } + Test::WaitForEventThreadTrigger(1); + + // Should trigger an Update without processing queue + application.SendNotification(); + application.Render(); + + Vector3 from, to; + adaptor.BuildPickingRay(Vector3(center), Vector3(center), from, to); // Hit test centre of screen + + { + auto accessor = adaptor.GetPhysicsAccessor(); + Vector3 localPivot; + float distanceFromCamera; + auto body = accessor->HitTest(from, from, localPivot, distanceFromCamera); + + DALI_TEST_CHECK(!body.Empty()); + } + + END_TEST; +} diff --git a/automated-tests/src/dali-physics/CMakeLists.txt b/automated-tests/src/dali-physics3d/CMakeLists.txt similarity index 91% rename from automated-tests/src/dali-physics/CMakeLists.txt rename to automated-tests/src/dali-physics3d/CMakeLists.txt index b6beab1..a863fd8 100644 --- a/automated-tests/src/dali-physics/CMakeLists.txt +++ b/automated-tests/src/dali-physics3d/CMakeLists.txt @@ -1,10 +1,8 @@ -SET(PKG_NAME "dali-physics") +SET(PKG_NAME "dali-physics3d") SET(EXEC_NAME "tct-${PKG_NAME}-core") SET(RPM_NAME "core-${PKG_NAME}-tests") -SET(CAPI_LIB "dali-physics") - # List of test case sources (Only these get parsed for test cases) SET(TC_SOURCES utc-Dali-PhysicsAdaptor.cpp @@ -58,7 +56,7 @@ SET(TEST_HARNESS_SOURCES ${TEST_HARNESS_DIR}/test-trace-call-stack.cpp ) -PKG_CHECK_MODULES(${CAPI_LIB} REQUIRED +PKG_CHECK_MODULES(${PKG_NAME} REQUIRED dali2-core dali2-adaptor dali2-toolkit @@ -67,17 +65,17 @@ PKG_CHECK_MODULES(${CAPI_LIB} REQUIRED ) ADD_COMPILE_OPTIONS( -O0 -ggdb --coverage -Wall -Werror -DDEBUG_ENABLED) -ADD_COMPILE_OPTIONS( ${${CAPI_LIB}_CFLAGS_OTHER} ) +ADD_COMPILE_OPTIONS( ${${PKG_NAME}_CFLAGS_OTHER} ) ADD_DEFINITIONS(-DTEST_RESOURCE_DIR=\"${CMAKE_CURRENT_SOURCE_DIR}/../../resources\" ) -FOREACH(directory ${${CAPI_LIB}_LIBRARY_DIRS}) +FOREACH(directory ${${PKG_NAME}_LIBRARY_DIRS}) SET(CMAKE_CXX_LINK_FLAGS "${CMAKE_CXX_LINK_FLAGS} -L${directory}") -ENDFOREACH(directory ${CAPI_LIB_LIBRARY_DIRS}) +ENDFOREACH(directory ${PKG_NAME_LIBRARY_DIRS}) INCLUDE_DIRECTORIES( ../../../ - ${${CAPI_LIB}_INCLUDE_DIRS} + ${${PKG_NAME}_INCLUDE_DIRS} ../dali-toolkit/dali-toolkit-test-utils ) @@ -90,7 +88,7 @@ ADD_CUSTOM_COMMAND( ADD_EXECUTABLE(${EXEC_NAME} ${EXEC_NAME}.h ${EXEC_NAME}.cpp ${TC_SOURCES} ${TEST_HARNESS_SOURCES}) TARGET_LINK_LIBRARIES(${EXEC_NAME} - ${${CAPI_LIB}_LIBRARIES} + ${${PKG_NAME}_LIBRARIES} -lpthread -ldl --coverage ) diff --git a/automated-tests/src/dali-physics3d/tct-dali-physics3d-core.cpp b/automated-tests/src/dali-physics3d/tct-dali-physics3d-core.cpp new file mode 100644 index 0000000..a87b21c --- /dev/null +++ b/automated-tests/src/dali-physics3d/tct-dali-physics3d-core.cpp @@ -0,0 +1,9 @@ +#include + +// Must come second +#include "tct-dali-physics3d-core.h" + +int main(int argc, char* const argv[]) +{ + return TestHarness::RunTests(argc, argv, tc_array); +} diff --git a/automated-tests/src/dali-physics/utc-Dali-PhysicsActor.cpp b/automated-tests/src/dali-physics3d/utc-Dali-PhysicsActor.cpp similarity index 95% rename from automated-tests/src/dali-physics/utc-Dali-PhysicsActor.cpp rename to automated-tests/src/dali-physics3d/utc-Dali-PhysicsActor.cpp index e1266e8..2c31d11 100644 --- a/automated-tests/src/dali-physics/utc-Dali-PhysicsActor.cpp +++ b/automated-tests/src/dali-physics3d/utc-Dali-PhysicsActor.cpp @@ -34,7 +34,7 @@ extern btRigidBody* CreateBody(btDiscreteDynamicsWorld* bulletWorld); const char* BALL_IMAGE = TEST_RESOURCE_DIR "/gallery-small-1.jpg"; -int UtcDaliPhysicsActorNew(void) +int UtcDaliPhysics3DActorNew(void) { ToolkitTestApplication application; @@ -55,7 +55,7 @@ int UtcDaliPhysicsActorNew(void) END_TEST; } -int UtcDaliPhysicsActorDownCastP(void) +int UtcDaliPhysics3DActorDownCastP(void) { ToolkitTestApplication application; @@ -78,7 +78,7 @@ int UtcDaliPhysicsActorDownCastP(void) END_TEST; } -int UtcDaliPhysicsActorDownCastN(void) +int UtcDaliPhysics3DActorDownCastN(void) { BaseHandle uninitializedHandle; PhysicsActor actor = PhysicsActor::DownCast(uninitializedHandle); @@ -86,7 +86,7 @@ int UtcDaliPhysicsActorDownCastN(void) END_TEST; } -int UtcDaliPhysicsActorMoveConstructor(void) +int UtcDaliPhysics3DActorMoveConstructor(void) { ToolkitTestApplication application; tet_infoline("Testing the move constructor"); @@ -114,7 +114,7 @@ int UtcDaliPhysicsActorMoveConstructor(void) END_TEST; } -int UtcDaliPhysicsActorCopyConstructor(void) +int UtcDaliPhysics3DActorCopyConstructor(void) { ToolkitTestApplication application; tet_infoline("Testing the move constructor"); @@ -142,7 +142,7 @@ int UtcDaliPhysicsActorCopyConstructor(void) END_TEST; } -int UtcDaliPhysicsActorCopyAssign(void) +int UtcDaliPhysics3DActorCopyAssign(void) { ToolkitTestApplication application; tet_infoline("Testing the copy assign"); @@ -170,7 +170,7 @@ int UtcDaliPhysicsActorCopyAssign(void) END_TEST; } -int UtcDaliPhysicsActorMoveAssignment(void) +int UtcDaliPhysics3DActorMoveAssignment(void) { ToolkitTestApplication application; tet_infoline("Testing the move constructor"); @@ -198,7 +198,7 @@ int UtcDaliPhysicsActorMoveAssignment(void) END_TEST; } -int UtcDaliPhysicsActorGetIdP(void) +int UtcDaliPhysics3DActorGetIdP(void) { ToolkitTestApplication application; tet_infoline("Testing the ID Getter"); @@ -220,7 +220,7 @@ int UtcDaliPhysicsActorGetIdP(void) END_TEST; } -int UtcDaliPhysicsActorGetIdN(void) +int UtcDaliPhysics3DActorGetIdN(void) { ToolkitTestApplication application; tet_infoline("Testing the ID Getter"); @@ -239,7 +239,7 @@ int UtcDaliPhysicsActorGetIdN(void) END_TEST; } -int UtcDaliPhysicsActorGetBodyP(void) +int UtcDaliPhysics3DActorGetBodyP(void) { ToolkitTestApplication application; tet_infoline("Testing the body Getter"); @@ -271,7 +271,7 @@ int UtcDaliPhysicsActorGetBodyP(void) END_TEST; } -int UtcDaliPhysicsActorGetBodyN(void) +int UtcDaliPhysics3DActorGetBodyN(void) { ToolkitTestApplication application; tet_infoline("Testing the ID Getter"); @@ -289,7 +289,7 @@ int UtcDaliPhysicsActorGetBodyN(void) END_TEST; } -int UtcDaliPhysicsActorSetPosition(void) +int UtcDaliPhysics3DActorSetPosition(void) { tet_infoline("Test the AsyncSetPhysicsPosition() function"); @@ -333,7 +333,7 @@ int UtcDaliPhysicsActorSetPosition(void) END_TEST; } -int UtcDaliPhysicsActorSetRotation1(void) +int UtcDaliPhysics3DActorSetRotation1(void) { tet_infoline("Test the AsyncSetPhysicsRotation() function"); @@ -379,7 +379,7 @@ int UtcDaliPhysicsActorSetRotation1(void) END_TEST; } -int UtcDaliPhysicsActorSetRotation2(void) +int UtcDaliPhysics3DActorSetRotation2(void) { tet_infoline("Test the AsyncSetPhysicsRotation() function"); @@ -425,7 +425,7 @@ int UtcDaliPhysicsActorSetRotation2(void) END_TEST; } -int UtcDaliPhysicsActorGetActorPosition(void) +int UtcDaliPhysics3DActorGetActorPosition(void) { tet_infoline("Test the GetActorPosition() function"); @@ -466,7 +466,7 @@ int UtcDaliPhysicsActorGetActorPosition(void) END_TEST; } -int UtcDaliPhysicsActorGetActorRotation(void) +int UtcDaliPhysics3DActorGetActorRotation(void) { tet_infoline("Test the GetActorRotation() function"); @@ -507,7 +507,7 @@ int UtcDaliPhysicsActorGetActorRotation(void) END_TEST; } -int UtcDaliPhysicsActorGetPhysicsPosition(void) +int UtcDaliPhysics3DActorGetPhysicsPosition(void) { tet_infoline("Test the GetPhysicsPosition() function"); @@ -550,7 +550,7 @@ int UtcDaliPhysicsActorGetPhysicsPosition(void) END_TEST; } -int UtcDaliPhysicsActorGetPhysicsRotation(void) +int UtcDaliPhysics3DActorGetPhysicsRotation(void) { tet_infoline("Test the GetPhysicsRotation() function"); diff --git a/automated-tests/src/dali-physics/utc-Dali-PhysicsAdaptor.cpp b/automated-tests/src/dali-physics3d/utc-Dali-PhysicsAdaptor.cpp similarity index 83% rename from automated-tests/src/dali-physics/utc-Dali-PhysicsAdaptor.cpp rename to automated-tests/src/dali-physics3d/utc-Dali-PhysicsAdaptor.cpp index 01dae19..b09c8fc 100644 --- a/automated-tests/src/dali-physics/utc-Dali-PhysicsAdaptor.cpp +++ b/automated-tests/src/dali-physics3d/utc-Dali-PhysicsAdaptor.cpp @@ -62,7 +62,7 @@ btRigidBody* CreateBody(btDiscreteDynamicsWorld* bulletWorld) return body; } -int UtcDaliPhysicsCreateAdaptorP1(void) +int UtcDaliPhysics3DCreateAdaptorP1(void) { ToolkitTestApplication application; @@ -75,7 +75,7 @@ int UtcDaliPhysicsCreateAdaptorP1(void) END_TEST; } -int UtcDaliPhysicsCreateAdaptorN1(void) +int UtcDaliPhysics3DCreateAdaptorN1(void) { ToolkitTestApplication application; @@ -85,7 +85,7 @@ int UtcDaliPhysicsCreateAdaptorN1(void) END_TEST; } -int UtcDaliPhysicsDowncastP1(void) +int UtcDaliPhysics3DDowncastP1(void) { ToolkitTestApplication application; @@ -101,7 +101,7 @@ int UtcDaliPhysicsDowncastP1(void) END_TEST; } -int UtcDaliPhysicsDowncastN1(void) +int UtcDaliPhysics3DDowncastN1(void) { BaseHandle handle; auto adaptor = PhysicsAdaptor::DownCast(handle); @@ -111,7 +111,7 @@ int UtcDaliPhysicsDowncastN1(void) END_TEST; } -int UtcDaliPhysicsAdaptorMoveConstructor(void) +int UtcDaliPhysics3DAdaptorMoveConstructor(void) { ToolkitTestApplication application; tet_infoline("Testing the move constructor"); @@ -129,7 +129,7 @@ int UtcDaliPhysicsAdaptorMoveConstructor(void) END_TEST; } -int UtcDaliPhysicsAdaptorCopyConstructor(void) +int UtcDaliPhysics3DAdaptorCopyConstructor(void) { ToolkitTestApplication application; tet_infoline("Testing the move constructor"); @@ -148,7 +148,7 @@ int UtcDaliPhysicsAdaptorCopyConstructor(void) END_TEST; } -int UtcDaliPhysicsAdaptorCopyAssign(void) +int UtcDaliPhysics3DAdaptorCopyAssign(void) { ToolkitTestApplication application; tet_infoline("Testing the copy assign"); @@ -166,7 +166,7 @@ int UtcDaliPhysicsAdaptorCopyAssign(void) END_TEST; } -int UtcDaliPhysicsAdaptorMoveAssignment(void) +int UtcDaliPhysics3DAdaptorMoveAssignment(void) { ToolkitTestApplication application; tet_infoline("Testing the move constructor"); @@ -184,7 +184,7 @@ int UtcDaliPhysicsAdaptorMoveAssignment(void) END_TEST; } -int UtcDaliPhysicsSetTimestep(void) +int UtcDaliPhysics3DSetTimestep(void) { ToolkitTestApplication application; @@ -199,7 +199,7 @@ int UtcDaliPhysicsSetTimestep(void) END_TEST; } -int UtcDaliPhysicsGetTimestep(void) +int UtcDaliPhysics3DGetTimestep(void) { ToolkitTestApplication application; @@ -220,7 +220,7 @@ int UtcDaliPhysicsGetTimestep(void) END_TEST; } -int UtcDaliPhysicsGetPhysicsAccessorP1(void) +int UtcDaliPhysics3DGetPhysicsAccessorP1(void) { ToolkitTestApplication application; @@ -237,7 +237,7 @@ int UtcDaliPhysicsGetPhysicsAccessorP1(void) END_TEST; } -int UtcDaliPhysicsGetPhysicsAccessorN1(void) +int UtcDaliPhysics3DGetPhysicsAccessorN1(void) { ToolkitTestApplication application; @@ -259,7 +259,7 @@ int UtcDaliPhysicsGetPhysicsAccessorN1(void) END_TEST; } -int UtcDaliPhysicsAdaptorGetRootActor(void) +int UtcDaliPhysics3DAdaptorGetRootActor(void) { tet_infoline("Test that the root actor can be retrieved"); @@ -278,7 +278,7 @@ int UtcDaliPhysicsAdaptorGetRootActor(void) END_TEST; } -int UtcDaliPhysicsAdaptorCreateDebugLayer(void) +int UtcDaliPhysics3DAdaptorCreateDebugLayer(void) { ToolkitTestApplication application; Matrix transform(true); @@ -315,7 +315,7 @@ int UtcDaliPhysicsAdaptorCreateDebugLayer(void) END_TEST; } -int UtcDaliPhysicsAdaptorTranslateToPhysicsSpace1(void) +int UtcDaliPhysics3DAdaptorTranslateToPhysicsSpace1(void) { ToolkitTestApplication application; Matrix transform(false); @@ -330,7 +330,7 @@ int UtcDaliPhysicsAdaptorTranslateToPhysicsSpace1(void) END_TEST; } -int UtcDaliPhysicsAdaptorTranslateToPhysicsSpace2(void) +int UtcDaliPhysics3DAdaptorTranslateToPhysicsSpace2(void) { ToolkitTestApplication application; Matrix transform(false); @@ -346,7 +346,7 @@ int UtcDaliPhysicsAdaptorTranslateToPhysicsSpace2(void) END_TEST; } -int UtcDaliPhysicsAdaptorTranslateToPhysicsSpace3(void) +int UtcDaliPhysics3DAdaptorTranslateToPhysicsSpace3(void) { ToolkitTestApplication application; Matrix transform(false); @@ -364,7 +364,7 @@ int UtcDaliPhysicsAdaptorTranslateToPhysicsSpace3(void) END_TEST; } -int UtcDaliPhysicsAdaptorTranslateToPhysicsSpace4(void) +int UtcDaliPhysics3DAdaptorTranslateToPhysicsSpace4(void) { ToolkitTestApplication application; Matrix transform(false); @@ -382,7 +382,7 @@ int UtcDaliPhysicsAdaptorTranslateToPhysicsSpace4(void) END_TEST; } -int UtcDaliPhysicsAdaptorTranslateToPhysicsSpace5(void) +int UtcDaliPhysics3DAdaptorTranslateToPhysicsSpace5(void) { ToolkitTestApplication application; Matrix transform(false); @@ -400,7 +400,7 @@ int UtcDaliPhysicsAdaptorTranslateToPhysicsSpace5(void) END_TEST; } -int UtcDaliPhysicsAdaptorTranslateFromPhysicsSpace1(void) +int UtcDaliPhysics3DAdaptorTranslateFromPhysicsSpace1(void) { ToolkitTestApplication application; Matrix transform(false); @@ -418,7 +418,7 @@ int UtcDaliPhysicsAdaptorTranslateFromPhysicsSpace1(void) END_TEST; } -int UtcDaliPhysicsAdaptorConvertVectorToPhysicsSpace01(void) +int UtcDaliPhysics3DAdaptorConvertVectorToPhysicsSpace01(void) { ToolkitTestApplication application; Matrix transform(false); @@ -434,7 +434,7 @@ int UtcDaliPhysicsAdaptorConvertVectorToPhysicsSpace01(void) END_TEST; } -int UtcDaliPhysicsAdaptorConvertVectorToPhysicsSpace02(void) +int UtcDaliPhysics3DAdaptorConvertVectorToPhysicsSpace02(void) { ToolkitTestApplication application; Matrix transform(false); @@ -451,7 +451,7 @@ int UtcDaliPhysicsAdaptorConvertVectorToPhysicsSpace02(void) END_TEST; } -int UtcDaliPhysicsAdaptorConvertVectorFromPhysicsSpace01(void) +int UtcDaliPhysics3DAdaptorConvertVectorFromPhysicsSpace01(void) { ToolkitTestApplication application; Matrix transform(false); @@ -467,7 +467,7 @@ int UtcDaliPhysicsAdaptorConvertVectorFromPhysicsSpace01(void) END_TEST; } -int UtcDaliPhysicsAdaptorConvertVectorFromPhysicsSpace02(void) +int UtcDaliPhysics3DAdaptorConvertVectorFromPhysicsSpace02(void) { ToolkitTestApplication application; Matrix transform(false); @@ -484,7 +484,7 @@ int UtcDaliPhysicsAdaptorConvertVectorFromPhysicsSpace02(void) END_TEST; } -int UtcDaliPhysicsAdaptorSetTransformAndSize(void) +int UtcDaliPhysics3DAdaptorSetTransformAndSize(void) { ToolkitTestApplication application; Matrix transform(false); @@ -506,7 +506,7 @@ int UtcDaliPhysicsAdaptorSetTransformAndSize(void) END_TEST; } -int UtcDaliPhysicsAdaptorSetIntegrationState(void) +int UtcDaliPhysics3DAdaptorSetIntegrationState(void) { tet_infoline("Test that changing the integration state is reflected"); @@ -527,7 +527,7 @@ int UtcDaliPhysicsAdaptorSetIntegrationState(void) END_TEST; } -int UtcDaliPhysicsAdaptorGetIntegrationState(void) +int UtcDaliPhysics3DAdaptorGetIntegrationState(void) { tet_infoline("Test that changing the integration state is reflected"); @@ -550,7 +550,7 @@ int UtcDaliPhysicsAdaptorGetIntegrationState(void) END_TEST; } -int UtcDaliPhysicsAdaptorSetDebugState(void) +int UtcDaliPhysics3DAdaptorSetDebugState(void) { tet_infoline("Test that changing the debug state is reflected"); @@ -574,7 +574,7 @@ int UtcDaliPhysicsAdaptorSetDebugState(void) END_TEST; } -int UtcDaliPhysicsAdaptorGetDebugState(void) +int UtcDaliPhysics3DAdaptorGetDebugState(void) { tet_infoline("Test that changing the debug state is reflected"); @@ -597,7 +597,7 @@ int UtcDaliPhysicsAdaptorGetDebugState(void) END_TEST; } -int UtcDaliPhysicsAdaptorAddActorBody(void) +int UtcDaliPhysics3DAdaptorAddActorBody(void) { tet_infoline("Test that an actor/body pair can be added"); @@ -626,7 +626,123 @@ int UtcDaliPhysicsAdaptorAddActorBody(void) END_TEST; } -int UtcDaliPhysicsAdaptorGetPhysicsActor(void) +int UtcDaliPhysics3DAdaptorRemoveActorBodyP01(void) +{ + tet_infoline("Test that an actor/body pair can be removed"); + + ToolkitTestApplication application; + Matrix transform(false); + transform.SetIdentityAndScale(Vector3(2.0f, 2.0f, 2.0f)); + Uint16Pair size(640, 480); + auto scene = application.GetScene(); + PhysicsAdaptor adaptor = PhysicsAdaptor::New(transform, size); + Actor rootActor = adaptor.GetRootActor(); + scene.Add(rootActor); + + btRigidBody* body; + { + auto accessor = adaptor.GetPhysicsAccessor(); + auto bulletWorld = accessor->GetNative().Get(); + + body = CreateBody(bulletWorld); + } + Dali::Actor ballActor = Toolkit::ImageView::New("gallery-small-1.jpg"); + auto physicsActor = adaptor.AddActorBody(ballActor, body); + + application.SendNotification(); + application.Render(); + application.SendNotification(); + application.Render(); + + adaptor.RemoveActorBody(physicsActor); + DALI_TEST_CHECK(!ballActor.GetParent()); + + { + auto accessor = adaptor.GetPhysicsAccessor(); + auto bulletWorld = accessor->GetNative().Get(); + + bulletWorld->removeRigidBody(body); + try + { + delete body; + tet_result(TET_PASS); + } + catch(std::exception& e) + { + tet_result(TET_FAIL); + } + } + + END_TEST; +} + +int UtcDaliPhysics3DAdaptorRemoveActorBodyN01(void) +{ + tet_infoline("Test that an empty actor/body pair doesn't break adaptor"); + + ToolkitTestApplication application; + Matrix transform(false); + transform.SetIdentityAndScale(Vector3(2.0f, 2.0f, 2.0f)); + Uint16Pair size(640, 480); + auto scene = application.GetScene(); + PhysicsAdaptor adaptor = PhysicsAdaptor::New(transform, size); + Actor rootActor = adaptor.GetRootActor(); + scene.Add(rootActor); + + tet_infoline("Test that removing a physics actor that hasn't been created with AddActorBody does nothing"); + + Dali::Actor actor = Dali::Actor::New(); + btRigidBody* body; + { + auto accessor = adaptor.GetPhysicsAccessor(); + auto bulletWorld = accessor->GetNative().Get(); + + body = CreateBody(bulletWorld); + } + + PhysicsActor physicsActor = PhysicsActor::New(actor, body, adaptor); + ; + try + { + adaptor.RemoveActorBody(physicsActor); + tet_result(TET_PASS); + } + catch(std::exception& e) + { + tet_result(TET_FAIL); + } + + END_TEST; +} + +int UtcDaliPhysics3DAdaptorRemoveActorBodyN02(void) +{ + tet_infoline("Test that an empty actor/body pair doesn't break adaptor"); + + ToolkitTestApplication application; + Matrix transform(false); + transform.SetIdentityAndScale(Vector3(2.0f, 2.0f, 2.0f)); + Uint16Pair size(640, 480); + auto scene = application.GetScene(); + PhysicsAdaptor adaptor = PhysicsAdaptor::New(transform, size); + Actor rootActor = adaptor.GetRootActor(); + scene.Add(rootActor); + + PhysicsActor physicsActor; + try + { + adaptor.RemoveActorBody(physicsActor); + tet_result(TET_FAIL); + } + catch(DaliException& e) + { + DALI_TEST_ASSERT(e, "Physics actor handle is empty", TEST_LOCATION); + } + + END_TEST; +} + +int UtcDaliPhysics3DAdaptorGetPhysicsActor(void) { tet_infoline("Test that an actor/body pair can be retrieved"); @@ -655,7 +771,7 @@ int UtcDaliPhysicsAdaptorGetPhysicsActor(void) END_TEST; } -int UtcDaliPhysicsAdaptorBuildPickingRay(void) +int UtcDaliPhysics3DAdaptorBuildPickingRay(void) { tet_infoline("Test that a touch can be converted to a picking ray"); @@ -674,7 +790,7 @@ int UtcDaliPhysicsAdaptorBuildPickingRay(void) END_TEST; } -int UtcDaliPhysicsAdaptorProjectPoint(void) +int UtcDaliPhysics3DAdaptorProjectPoint(void) { tet_infoline("Test that a point is projected into physics space"); @@ -692,7 +808,7 @@ int UtcDaliPhysicsAdaptorProjectPoint(void) END_TEST; } -int UtcDaliPhysicsAdaptorQueue(void) +int UtcDaliPhysics3DAdaptorQueue(void) { tet_infoline("Test that Queue and CreateSyncPoint both work"); @@ -736,7 +852,7 @@ int UtcDaliPhysicsAdaptorQueue(void) END_TEST; } -int UtcDaliPhysicsAdaptorCreateSyncPoint(void) +int UtcDaliPhysics3DAdaptorCreateSyncPoint(void) { tet_infoline("Test that a delayed CreateSyncPoint delays update"); @@ -793,7 +909,7 @@ int UtcDaliPhysicsAdaptorCreateSyncPoint(void) END_TEST; } -int UtcDaliPhysicsAdaptorHitTestP(void) +int UtcDaliPhysics3DAdaptorHitTestP(void) { tet_infoline("Test that hit testing finds a body"); diff --git a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-compare-types.h b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-compare-types.h index fcadd6f..a31f162 100644 --- a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-compare-types.h +++ b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-compare-types.h @@ -2,7 +2,7 @@ #define DALI_TEST_COMPARE_TYPES_H /* - * Copyright (c) 2022 Samsung Electronics Co., Ltd. + * 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. @@ -27,9 +27,9 @@ inline bool CompareType(Type value1, Type value2, float epsilon) } /** - * A helper for fuzzy-comparing Vector2 objects - * @param[in] vector1 the first object - * @param[in] vector2 the second object + * A helper for matching floats + * @param[in] value1 the first object + * @param[in] value2 the second object * @param[in] epsilon difference threshold * @returns true if difference is smaller than epsilon threshold, false otherwise */ @@ -40,6 +40,19 @@ inline bool CompareType(float value1, float value2, float epsilon) } /** + * A helper for matching doubles + * @param[in] value1 the first object + * @param[in] value2 the second object + * @param[in] epsilon difference threshold + * @returns true if difference is smaller than epsilon threshold, false otherwise + */ +template<> +inline bool CompareType(double value1, double value2, float epsilon) +{ + return fabs(value1 - value2) < double(epsilon); +} + +/** * A helper for fuzzy-comparing Vector2 objects * @param[in] vector1 the first object * @param[in] vector2 the second object diff --git a/build/tizen/dali-physics/CMakeLists.txt b/build/tizen/dali-physics/CMakeLists.txt index 5bf2ff8..00c482b 100644 --- a/build/tizen/dali-physics/CMakeLists.txt +++ b/build/tizen/dali-physics/CMakeLists.txt @@ -33,7 +33,7 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${extra_flags}") set(prefix ${CMAKE_INSTALL_PREFIX}) -set(repo_root_dir "${CMAKE_CURRENT_LIST_DIR}/../../../") +set(repo_root_dir "${CMAKE_CURRENT_LIST_DIR}/../../..") set(physics_dir "${repo_root_dir}/dali-physics") option(ENABLE_PKG_CONFIGURE "Use pkgconfig" ON) @@ -70,10 +70,9 @@ endif() add_subdirectory("${physics_dir}/third-party/chipmunk2d" chipmunk2d) add_subdirectory("${physics_dir}/third-party/bullet3" bullet3) -# TODO: Split into 2 separate targets -set(physics3d_src_files "") -include("${physics_dir}/public-api/file.list") -include("${physics_dir}/internal/file.list") +set(physics_src_files "") +include(${physics_dir}/public-api/file.list) +include(${physics_dir}/internal/file.list) set(prefix_include_dir "${prefix}/include") include_directories(${repo_root_dir} @@ -81,13 +80,22 @@ include_directories(${repo_root_dir} "${repo_root_dir}/dali-physics/third-party/bullet3/src" ) -MESSAGE( STATUS "SOURCES: " ${physics3d_src_files}) +MESSAGE(STATUS "2D sources: ${physics2d_src_files}") +MESSAGE(STATUS "3D sources: ${physics3d_src_files}") + +ADD_LIBRARY("${name}-2d" SHARED ${physics2d_src_files} ) +TARGET_LINK_LIBRARIES("${name}-2d" ${DALICORE_LDFLAGS} + dali2-toolkit + chipmunk + ${COVERAGE}) +TARGET_COMPILE_OPTIONS("${name}-2d" PUBLIC "-I${repo_root_dir}/dali-physics/third-party/chipmunk2d/include") ADD_LIBRARY("${name}-3d" SHARED ${physics3d_src_files} ) TARGET_LINK_LIBRARIES("${name}-3d" ${DALICORE_LDFLAGS} dali2-toolkit bullet3 ${COVERAGE}) +TARGET_COMPILE_OPTIONS("${name}-3d" PUBLIC "-I${repo_root_dir}/dali-physics/third-party/bullet3/src") IF (ENABLE_PKG_CONFIGURE) INSTALL(FILES @@ -99,6 +107,13 @@ ENDIF() IF( INSTALL_CMAKE_MODULES ) MESSAGE(STATUS "Installing cmake modules & libs") + SET_TARGET_PROPERTIES( ${name}-2d + PROPERTIES + VERSION ${DALI_PHYSICS_VERSION} + SOVERSION ${${name}_VERSION_MAJOR} + CLEAN_DIRECT_OUPUT 1 + ) + SET_TARGET_PROPERTIES( ${name}-3d PROPERTIES VERSION ${DALI_PHYSICS_VERSION} @@ -112,6 +127,13 @@ IF( INSTALL_CMAKE_MODULES ) ENDIF() # Install library + INSTALL( TARGETS ${name}-2d + EXPORT ${name}-2d-targets + LIBRARY DESTINATION ${LIB_DIR} + ARCHIVE DESTINATION ${LIB_DIR} + RUNTIME DESTINATION ${BIN_DIR} + ) + INSTALL( TARGETS ${name}-3d EXPORT ${name}-3d-targets LIBRARY DESTINATION ${LIB_DIR} @@ -121,6 +143,13 @@ IF( INSTALL_CMAKE_MODULES ) # Install the cmake modules. INSTALL( + EXPORT ${name}-2d-targets + NAMESPACE ${name}-2d:: + FILE ${name}-2d-targets.cmake + DESTINATION share/${name}-2d + ) + + INSTALL( EXPORT ${name}-3d-targets NAMESPACE ${name}-3d:: FILE ${name}-3d-targets.cmake @@ -141,12 +170,13 @@ IF( INSTALL_CMAKE_MODULES ) ELSE() MESSAGE(STATUS "Installing libs") + INSTALL( TARGETS ${name}-2d DESTINATION ${LIB_DIR} ) INSTALL( TARGETS ${name}-3d DESTINATION ${LIB_DIR} ) ENDIF() # Install headers -install( FILES ${physics3d_public_api_header_files} +install( FILES ${physics_public_api_header_files} DESTINATION "${INCLUDE_DIR}/dali-physics/public-api" ) diff --git a/build/tizen/dali-physics/dali2-physics-2d.pc.in b/build/tizen/dali-physics/dali2-physics-2d.pc.in index 75f9216..29dcbc1 100644 --- a/build/tizen/dali-physics/dali2-physics-2d.pc.in +++ b/build/tizen/dali-physics/dali2-physics-2d.pc.in @@ -8,5 +8,5 @@ Name: DALi Engine Physics Library Description: Dali Physics 2D library Version: ${apiversion} Requires: chipmunk2d -Libs: -L${libdir} +Libs: -L${libdir} -ldali2-physics-2d Cflags: -I${includedir} diff --git a/dali-physics/internal/physics-actor-impl.cpp b/dali-physics/internal/bullet-impl/bullet-physics-actor-impl.cpp similarity index 98% rename from dali-physics/internal/physics-actor-impl.cpp rename to dali-physics/internal/bullet-impl/bullet-physics-actor-impl.cpp index 9f9d467..eec3929 100644 --- a/dali-physics/internal/physics-actor-impl.cpp +++ b/dali-physics/internal/bullet-impl/bullet-physics-actor-impl.cpp @@ -16,6 +16,8 @@ // Class Header #include + +#include #include namespace Dali::Toolkit::Physics::Internal @@ -60,7 +62,6 @@ PhysicsActor::~PhysicsActor() = default; void PhysicsActor::Initialize(void) { - // RegisterObject? } void PhysicsActor::AsyncSetPhysicsPosition(Dali::Vector3 actorPosition) @@ -105,7 +106,6 @@ Dali::Quaternion PhysicsActor::GetActorRotation() const const btTransform& transform = body->getWorldTransform(); btQuaternion q = transform.getRotation(); return mAdaptor.TranslateFromPhysicsSpace(Quaternion(q.w(), q.x(), q.y(), q.z())); - } } // namespace Dali::Toolkit::Physics::Internal diff --git a/dali-physics/internal/bullet-impl/bullet-physics-adaptor-impl.cpp b/dali-physics/internal/bullet-impl/bullet-physics-adaptor-impl.cpp new file mode 100644 index 0000000..9e36059 --- /dev/null +++ b/dali-physics/internal/bullet-impl/bullet-physics-adaptor-impl.cpp @@ -0,0 +1,251 @@ +/* + * 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. + */ + +// Class Header +#include + +// External Headers +#include +#include + +// Internal Headers +#include +#include +#include +#include +#include + +namespace +{ +#if defined(DEBUG_ENABLED) +Debug::Filter* gLogFilter = Debug::Filter::New(Debug::Concise, false, "LOG_PHYSICS"); +#endif + +} // namespace + +namespace Dali::Toolkit::Physics::Internal +{ +PhysicsAdaptorPtr CreateNewPhysicsAdaptor(const Dali::Matrix& transform, Uint16Pair worldSize) +{ + PhysicsAdaptorPtr adaptor(new BulletPhysicsAdaptor()); + adaptor->Initialize(transform, worldSize); + return adaptor; +} + +BulletPhysicsAdaptor::BulletPhysicsAdaptor() +: PhysicsAdaptor() +{ +} + +BulletPhysicsAdaptor::~BulletPhysicsAdaptor() +{ + // @todo Ensure physics bodies don't leak +} + +void BulletPhysicsAdaptor::OnInitialize(const Dali::Matrix& transform, Uint16Pair worldSize) +{ + mTransform = transform; + mInverseTransform = transform; + mInverseTransform.Invert(); + mSize = worldSize; + + mPhysicsWorld = BulletPhysicsWorld::New(mRootActor, + Dali::MakeCallback(mSlotDelegate.GetSlot(), + &PhysicsAdaptor::OnUpdateActors)); +} + +Layer BulletPhysicsAdaptor::CreateDebugLayer(Dali::Window window) +{ + Layer debugLayer; + + auto renderTaskList = window.GetRenderTaskList(); + auto renderTask = renderTaskList.GetTask(0); + auto windowSize = window.GetSize(); + + debugLayer = Layer::New(); + debugLayer[Actor::Property::NAME] = "PhysicsDebugLayer"; + debugLayer[Actor::Property::ANCHOR_POINT] = Dali::AnchorPoint::CENTER; + debugLayer[Actor::Property::PARENT_ORIGIN] = Dali::ParentOrigin::CENTER; + + Constraint positionConstraint = Constraint::New(debugLayer, Actor::Property::POSITION, EqualToConstraint()); + positionConstraint.AddSource(Source(mRootActor, Actor::Property::POSITION)); + positionConstraint.Apply(); + Constraint sizeConstraint = Constraint::New(debugLayer, Actor::Property::SIZE, EqualToConstraint()); + sizeConstraint.AddSource(Source(mRootActor, Actor::Property::SIZE)); + sizeConstraint.Apply(); + + mDebugRenderer = PhysicsDebugRenderer::New(windowSize.GetWidth(), windowSize.GetHeight(), renderTask.GetCameraActor(), this); + mDebugActor = DrawableActor::New(*(mDebugRenderer->GetCallback().get())); + mDebugActor[Actor::Property::ANCHOR_POINT] = Dali::AnchorPoint::CENTER; + mDebugActor[Actor::Property::PARENT_ORIGIN] = Dali::ParentOrigin::CENTER; + + Constraint sizeConstraint2 = Constraint::New(mDebugActor, Actor::Property::SIZE, EqualToConstraint()); + sizeConstraint2.AddSource(ParentSource(Actor::Property::SIZE)); + sizeConstraint2.Apply(); + + debugLayer.Add(mDebugActor); + + auto bulletWorld = mPhysicsWorld->GetNative().Get(); + + bulletWorld->setDebugDrawer(mDebugRenderer.get()); + mDebugRenderer->setDebugMode(btIDebugDraw::DBG_DrawWireframe | + btIDebugDraw::DBG_DrawContactPoints | + btIDebugDraw::DBG_DrawNormals); + + window.Add(debugLayer); + return debugLayer; +} + +void BulletPhysicsAdaptor::SetTransformAndSize(const Dali::Matrix& transform, Uint16Pair worldSize) +{ + mTransform = transform; + mInverseTransform = transform; + mInverseTransform.Invert(); + mSize = worldSize; + + GetRootActor()[Actor::Property::SIZE] = Vector3(worldSize.GetWidth(), worldSize.GetHeight(), 0); + + if(mDebugRenderer) + { + Actor layer = mDebugActor.GetParent(); + layer[Actor::Property::SIZE] = Vector3(worldSize); + mDebugRenderer->UpdateWindowSize(worldSize); + } +} + +PhysicsActorPtr BulletPhysicsAdaptor::AddActorBody(Dali::Actor actor, Dali::Any body) +{ + uint32_t id = static_cast(actor.GetProperty(Actor::Property::ID)); + btRigidBody* btBody = body.Get(); + + btBody->setUserIndex(id); + mPhysicsActors.insert(std::make_pair(id, PhysicsActor::New(actor, body, *this))); + actor[Actor::Property::PARENT_ORIGIN] = Dali::ParentOrigin::CENTER; + actor[Actor::Property::ANCHOR_POINT] = Dali::AnchorPoint::CENTER; + mRootActor.Add(actor); + return mPhysicsActors.at(id); +} + +void BulletPhysicsAdaptor::RemoveActorBody(PhysicsActor& physicsActor) +{ + auto iter = mPhysicsActors.find(physicsActor.GetId()); + if(iter != mPhysicsActors.end()) + { + mPhysicsActors.erase(iter); + } + Dali::Actor actor = mRootActor.FindChildById(physicsActor.GetId()); + if(actor) + { + actor.Unparent(); + } + + auto body = physicsActor.GetBody(); + btRigidBody* btBody = body.Get(); + if(btBody) + { + btBody->setUserIndex(-1); + } +} + +PhysicsActorPtr BulletPhysicsAdaptor::GetPhysicsActor(Dali::Any body) const +{ + btRigidBody* btBody = body.Get(); + if(btBody) + { + int id = btBody->getUserIndex(); + auto iter = mPhysicsActors.find(id); + if(iter != mPhysicsActors.end()) + { + return iter->second; + } + } + DALI_LOG_ERROR("Body not found in physics actors"); + return nullptr; +} + +// Convert a position from root actor local space to physics space +Vector3 BulletPhysicsAdaptor::TranslateToPhysicsSpace(Vector3 vector) const +{ + Vector4 position = mTransform * Vector4(vector.x, vector.y, vector.z, 1.0f); + return Vector3(position); +} + +// Convert a position from physics space to root actor local space +Vector3 BulletPhysicsAdaptor::TranslateFromPhysicsSpace(Vector3 vector) const +{ + Vector4 position = mInverseTransform * Vector4(vector.x, vector.y, vector.z, 1.0f); + return Vector3(position); +} + +Quaternion BulletPhysicsAdaptor::TranslateToPhysicsSpace(Quaternion orientation) const +{ + // Naive check for speed. Should pass scale in constructor/transform setter + + if(std::signbit(mTransform.AsFloat()[0])) // mirrored in x + { + return Quaternion(orientation.mVector.w, orientation.mVector.x, -orientation.mVector.y, -orientation.mVector.z); + } + else if(std::signbit(mTransform.AsFloat()[5])) // mirrored in y + { + return Quaternion(orientation.mVector.w, -orientation.mVector.x, orientation.mVector.y, -orientation.mVector.z); + } + else if(std::signbit(mTransform.AsFloat()[10])) // mirrored in z + { + return Quaternion(orientation.mVector.w, -orientation.mVector.x, -orientation.mVector.y, orientation.mVector.z); + } + + // No mirror, so rotation is invariant. + return orientation; +} + +Quaternion BulletPhysicsAdaptor::TranslateFromPhysicsSpace(Quaternion orientation) const +{ + // Mirroring conversion is identical in both transforms + return TranslateToPhysicsSpace(orientation); +} + +// Convert a vector from dali space to physics space +Vector3 BulletPhysicsAdaptor::ConvertVectorToPhysicsSpace(Vector3 vector) const +{ + Vector4 otherVector(mTransform * Vector4(vector.x, vector.y, vector.z, 0.0f)); + return Vector3(otherVector); +} + +// Convert a vector from physics space to root actor local space +Vector3 BulletPhysicsAdaptor::ConvertVectorFromPhysicsSpace(Vector3 vector) const +{ + Vector4 otherVector(mInverseTransform * Vector4(vector.x, vector.y, vector.z, 0.0f)); + return Vector3(otherVector); +} + +void BulletPhysicsAdaptor::BuildPickingRay(Vector3 origin, Vector3 direction, Dali::Vector3& rayFromWorld, Dali::Vector3& rayToWorld) +{ + rayFromWorld = TranslateToPhysicsSpace(origin); + rayToWorld = TranslateToPhysicsSpace(origin + direction * 10000.0f); +} + +Vector3 BulletPhysicsAdaptor::ProjectPoint(Vector3 origin, Vector3 direction, float distance) +{ + Vector3 rayFromWorld = TranslateToPhysicsSpace(origin); + Vector3 rayToWorld = TranslateToPhysicsSpace(origin + direction * 10000.0f); + + Vector3 dir = rayToWorld - rayFromWorld; + dir.Normalize(); + dir *= distance; + return (rayFromWorld + dir); +} + +} // namespace Dali::Toolkit::Physics::Internal diff --git a/dali-physics/internal/bullet-impl/bullet-physics-adaptor-impl.h b/dali-physics/internal/bullet-impl/bullet-physics-adaptor-impl.h new file mode 100644 index 0000000..3c9001a --- /dev/null +++ b/dali-physics/internal/bullet-impl/bullet-physics-adaptor-impl.h @@ -0,0 +1,121 @@ +#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 adaptoried. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// EXTERNAL INCLUDES + +// INTERNAL INCLUDES +#include +#include + +namespace Dali::Toolkit::Physics::Internal +{ +class PhysicsDebugRenderer; + +class BulletPhysicsAdaptor : public PhysicsAdaptor +{ +public: + BulletPhysicsAdaptor(); + + /** + * A reference counted object may only be deleted by calling Unreference() + */ + ~BulletPhysicsAdaptor() override; + + // Remove copy constructor and copy assignment + BulletPhysicsAdaptor(const PhysicsAdaptor& handle) = delete; + BulletPhysicsAdaptor& operator=(const PhysicsAdaptor& handle) = delete; + + static PhysicsAdaptorPtr New(const Dali::Matrix& transform, Uint16Pair size); + + /** + * 2nd stage initialization + */ + void Initialize(const Dali::Matrix& transform, Uint16Pair size); + void OnInitialize(const Dali::Matrix& transform, Uint16Pair size) override; + + /** + * @copydoc Dali::Toolkit::Physics::PhysicsAdaptor::CreateDebugLayer + */ + Dali::Layer CreateDebugLayer(Dali::Window window) override; + + /** + * @copydoc Dali::Toolkit::Physics::PhysicsAdaptor::SetTransformAndSize + */ + void SetTransformAndSize(const Dali::Matrix& transform, Uint16Pair size) override; + + /** + * @copydoc Dali::Toolkit::Physics::PhysicsAdaptor::TranslateToPhysicsSpace + */ + Dali::Vector3 TranslateToPhysicsSpace(Dali::Vector3 vector) const override; + + /** + * @copydoc Dali::Toolkit::Physics::PhysicsAdaptor::TranslateToPhysicsSpace + */ + Dali::Quaternion TranslateToPhysicsSpace(Dali::Quaternion rotation) const override; + + /** + * @copydoc Dali::Toolkit::Physics::PhysicsAdaptor::TranslateFromPhysicsSpace + */ + Dali::Vector3 TranslateFromPhysicsSpace(Dali::Vector3 vector) const override; + + /** + * @copydoc Dali::Toolkit::Physics::PhysicsAdaptor::TranslateFromPhysicsSpace + */ + Dali::Quaternion TranslateFromPhysicsSpace(Quaternion rotation) const override; + + /** + * @copydoc Dali::Toolkit::Physics::PhysicsAdaptor::ConvertVectorToPhysicsSpace + */ + Dali::Vector3 ConvertVectorToPhysicsSpace(Dali::Vector3 vector) const override; + + /** + * @copydoc Dali::Toolkit::Physics::PhysicsAdaptor::ConvertVectorFromPhysicsSpace + */ + Dali::Vector3 ConvertVectorFromPhysicsSpace(Dali::Vector3 vector) const override; + + /** + * @copydoc Dali::Toolkit::Physics::PhysicsAdaptor::AddActorBody + */ + PhysicsActorPtr AddActorBody(Dali::Actor actor, Dali::Any body) override; + + /** + * @copydoc Dali::Toolkit::Physics::PhysicsAdaptor::RemoveActorBody + */ + void RemoveActorBody(PhysicsActor& physicsActor) override; + + /** + * @copydoc Dali::Toolkit::Physics::PhysicsAdaptor::GetPhysicsActor + */ + PhysicsActorPtr GetPhysicsActor(Dali::Any body) const override; + + /** + * @copydoc Dali::Toolkit::Physics::PhysicsAdaptor::BuildPickingRay + */ + void BuildPickingRay(Dali::Vector3 origin, Dali::Vector3 direction, Dali::Vector3& rayFromWorld, Dali::Vector3& rayToWorld) override; + + /** + * @copydoc Dali::Toolkit::Physics::PhysicsAdaptor::ProjectPoint + */ + Dali::Vector3 ProjectPoint(Dali::Vector3 origin, Dali::Vector3 direction, float distance) override; + +private: + Actor mDebugActor; + std::unique_ptr mDebugRenderer; +}; + +} // namespace Dali::Toolkit::Physics::Internal diff --git a/dali-physics/internal/physics-debug-renderer.cpp b/dali-physics/internal/bullet-impl/bullet-physics-debug-renderer.cpp similarity index 97% rename from dali-physics/internal/physics-debug-renderer.cpp rename to dali-physics/internal/bullet-impl/bullet-physics-debug-renderer.cpp index c6a1421..d481b2e 100644 --- a/dali-physics/internal/physics-debug-renderer.cpp +++ b/dali-physics/internal/bullet-impl/bullet-physics-debug-renderer.cpp @@ -14,10 +14,14 @@ * limitations under the License. */ -#include "physics-debug-renderer.h" +// Class header +#include +// External Includes #include -#include "physics-adaptor-impl.h" + +// Internal Includes +#include using Dali::Degree; using Dali::Matrix; diff --git a/dali-physics/internal/physics-debug-renderer.h b/dali-physics/internal/bullet-impl/bullet-physics-debug-renderer.h similarity index 99% rename from dali-physics/internal/physics-debug-renderer.h rename to dali-physics/internal/bullet-impl/bullet-physics-debug-renderer.h index b7909e2..5c15601 100644 --- a/dali-physics/internal/physics-debug-renderer.h +++ b/dali-physics/internal/bullet-impl/bullet-physics-debug-renderer.h @@ -16,6 +16,7 @@ * limitations under the License. */ +// External includes #include #include #include diff --git a/dali-physics/internal/bullet-impl/bullet-physics-world-impl.cpp b/dali-physics/internal/bullet-impl/bullet-physics-world-impl.cpp new file mode 100644 index 0000000..79d97de --- /dev/null +++ b/dali-physics/internal/bullet-impl/bullet-physics-world-impl.cpp @@ -0,0 +1,154 @@ +/* + * 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. + */ + +// Class Header +#include + +// External Headers +#include +#include +#include + +// Internal Headers +#include +#include +#include + +namespace Dali::Toolkit::Physics::Internal +{ +std::unique_ptr BulletPhysicsWorld::New(Dali::Actor rootActor, Dali::CallbackBase* updateCallback) +{ + std::unique_ptr world = std::make_unique(rootActor, updateCallback); + world->Initialize(); + return world; +} + +BulletPhysicsWorld::BulletPhysicsWorld(Dali::Actor rootActor, Dali::CallbackBase* updateCallback) +: PhysicsWorld(rootActor, updateCallback) +{ +} + +void BulletPhysicsWorld::OnInitialize(/*void* dynamicsWorld*/) +{ + // @todo Should enable developer to supply their own created DynamicsWorld. + + mCollisionConfiguration = new btDefaultCollisionConfiguration(); + mDispatcher = new btCollisionDispatcher(mCollisionConfiguration); + mBroadphase = new btDbvtBroadphase(); + mSolver = new btSequentialImpulseConstraintSolver; + mDynamicsWorld = new btDiscreteDynamicsWorld(mDispatcher, mBroadphase, mSolver, mCollisionConfiguration); +} + +BulletPhysicsWorld::~BulletPhysicsWorld() +{ + Dali::Mutex::ScopedLock lock(mMutex); + + if(mDynamicsWorld) + { + int i; + for(i = mDynamicsWorld->getNumConstraints() - 1; i >= 0; i--) + { + mDynamicsWorld->removeConstraint(mDynamicsWorld->getConstraint(i)); + } + for(i = mDynamicsWorld->getNumCollisionObjects() - 1; i >= 0; i--) + { + btCollisionObject* obj = mDynamicsWorld->getCollisionObjectArray()[i]; + btRigidBody* body = btRigidBody::upcast(obj); + if(body && body->getMotionState()) + { + delete body->getMotionState(); + } + mDynamicsWorld->removeCollisionObject(obj); + delete obj; + } + } + + /* + for (int j = 0; j < m_collisionShapes.size(); j++) + { + btCollisionShape* shape = mCollisionShapes[j]; + delete shape; + } + mCollisionShapes.clear(); + */ + + delete mDynamicsWorld; + delete mSolver; + delete mBroadphase; + delete mDispatcher; + delete mCollisionConfiguration; +} + +Dali::Any BulletPhysicsWorld::GetNative() +{ + return mDynamicsWorld; +} + +void BulletPhysicsWorld::Integrate(float timestep) +{ + if(mPhysicsIntegrateState == Physics::PhysicsAdaptor::IntegrationState::ON) + { + mDynamicsWorld->stepSimulation(timestep); + } + if(mDynamicsWorld->getDebugDrawer() && mPhysicsDebugState == Physics::PhysicsAdaptor::DebugState::ON) + { + mDynamicsWorld->debugDrawWorld(); + } +} + +inline btVector3 ConvertVector(Dali::Vector3 vector) +{ + return btVector3(vector.x, vector.y, vector.z); +} + +Dali::Any BulletPhysicsWorld::HitTest(Dali::Vector3 rayFromWorld, Dali::Vector3 rayToWorld, Dali::Vector3& localPivot, float& distanceFromCamera) +{ + btRigidBody* hitBody{nullptr}; + + btVector3 origin = ConvertVector(rayFromWorld); + btVector3 end = ConvertVector(rayToWorld); + btCollisionWorld::ClosestRayResultCallback rayResultCallback(origin, end); + rayResultCallback.m_flags |= btTriangleRaycastCallback::kF_UseGjkConvexCastRaytest; + + mDynamicsWorld->rayTest(origin, end, rayResultCallback); + if(rayResultCallback.hasHit()) + { + auto pickPos = rayResultCallback.m_hitPointWorld; + btRigidBody* body = (btRigidBody*)btRigidBody::upcast(rayResultCallback.m_collisionObject); + if(body) + { + if(!(body->isStaticObject() || body->isKinematicObject())) + { + hitBody = body; // Found a dynamic body. + distanceFromCamera = (pickPos - origin).length(); + + btVector3 pivot = body->getCenterOfMassTransform().inverse() * pickPos; + localPivot.x = pivot.x(); + localPivot.y = pivot.y(); + localPivot.z = pivot.z(); + } + } + } + Dali::Any bodyPtr; + if(hitBody) + { + bodyPtr = hitBody; + } + + return bodyPtr; +} + +} // namespace Dali::Toolkit::Physics::Internal diff --git a/dali-physics/internal/bullet-impl/bullet-physics-world-impl.h b/dali-physics/internal/bullet-impl/bullet-physics-world-impl.h new file mode 100644 index 0000000..2a5ff55 --- /dev/null +++ b/dali-physics/internal/bullet-impl/bullet-physics-world-impl.h @@ -0,0 +1,67 @@ +#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 +#include + +#include +#include + +#include + +namespace Dali::Toolkit::Physics::Internal +{ +class PhysicsWorld; +class FrameCallback; + +class BulletPhysicsWorld : public PhysicsWorld +{ +public: + static std::unique_ptr New(Dali::Actor rootActor, Dali::CallbackBase* updateCallback); + + BulletPhysicsWorld(Dali::Actor rootActor, Dali::CallbackBase* updateCallback); + ~BulletPhysicsWorld(); + + void OnInitialize(/*void* dynamicsWorld*/) override; + + Dali::Any GetNative() override; + + /** + * Hit test the physics world and return the nearest body. + * + * @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[out] localPivot The hit point local to the body + * @param[out] distanceFromCamera The distance of the pick point from the camera + * @return Empty value if no dynamic body found, otherwise a valid ptr to the hit body. + */ + Dali::Any HitTest(Dali::Vector3 rayFromWorld, Dali::Vector3 rayToWorld, Dali::Vector3& localPivot, float& distanceFromCamera) override; + + void Integrate(float timestep) override; + +private: + btDiscreteDynamicsWorld* mDynamicsWorld{nullptr}; + btCollisionDispatcher* mDispatcher{nullptr}; + btDefaultCollisionConfiguration* mCollisionConfiguration{nullptr}; + btBroadphaseInterface* mBroadphase{nullptr}; + btSequentialImpulseConstraintSolver* mSolver{nullptr}; +}; + +} // namespace Dali::Toolkit::Physics::Internal diff --git a/dali-physics/internal/chipmunk-impl/chipmunk-physics-actor-impl.cpp b/dali-physics/internal/chipmunk-impl/chipmunk-physics-actor-impl.cpp new file mode 100644 index 0000000..eee9cd4 --- /dev/null +++ b/dali-physics/internal/chipmunk-impl/chipmunk-physics-actor-impl.cpp @@ -0,0 +1,108 @@ +/* + * 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. + */ + +// Class Header +#include +#include + +#include + +namespace +{ +inline cpVect fromVec3(Dali::Vector3 vec3) +{ + return cpv(vec3.x, vec3.y); +} + +inline Dali::Vector3 toVec3(cpVect vec) +{ + return Dali::Vector3(vec.x, vec.y, 0.0f); +} + +} //Anonymous namespace + +namespace Dali::Toolkit::Physics::Internal +{ +PhysicsActorPtr PhysicsActor::New(Dali::Actor actor, Dali::Any body, Dali::Toolkit::Physics::Internal::PhysicsAdaptor& adaptor) +{ + PhysicsActorPtr physicsActor(new Internal::PhysicsActor(actor, body, adaptor)); + physicsActor->Initialize(); + return physicsActor; +} + +PhysicsActor::PhysicsActor(Dali::Actor actor, Dali::Any body, PhysicsAdaptor& adaptor) +: mAdaptor(adaptor), + mActorId(actor.GetProperty(Dali::Actor::Property::ID)), + mBody(body) +{ +} + +PhysicsActor::~PhysicsActor() = default; + +void PhysicsActor::Initialize(void) +{ + cpBodySetUserData(mBody.Get(), this); + + // RegisterObject? +} + +void PhysicsActor::AsyncSetPhysicsPosition(Dali::Vector3 actorPosition) +{ + // Queue task + cpBody* body = mBody.Get(); + cpVect pos = fromVec3(mAdaptor.TranslateToPhysicsSpace(actorPosition)); + mAdaptor.Queue([body, pos] { cpBodySetPosition(body, pos); }); +} + +void PhysicsActor::AsyncSetPhysicsRotation(Dali::Quaternion rotation) +{ + // Queue task + cpBody* body = mBody.Get(); + auto q = mAdaptor.TranslateToPhysicsSpace(rotation); + Vector3 axis; + Radian angle; + q.ToAxisAngle(axis, angle); + mAdaptor.Queue([body, angle]() { cpBodySetAngle(body, angle); }); +} + +Dali::Vector3 PhysicsActor::GetPhysicsPosition() const +{ + cpBody* body = mBody.Get(); + return toVec3(cpBodyGetPosition(body)); +} + +Dali::Quaternion PhysicsActor::GetPhysicsRotation() const +{ + cpBody* body = mBody.Get(); + cpFloat angle = cpBodyGetAngle(body); + return Quaternion(Radian(angle), Vector3::ZAXIS); +} + +Dali::Vector3 PhysicsActor::GetActorPosition() const +{ + cpBody* body = mBody.Get(); + cpVect cpPosition = cpBodyGetPosition(body); + return mAdaptor.TranslateFromPhysicsSpace(Vector3(cpPosition.x, cpPosition.y, 0.0f)); +} + +Dali::Quaternion PhysicsActor::GetActorRotation() const +{ + cpBody* body = mBody.Get(); + cpFloat angle = cpBodyGetAngle(body); + return mAdaptor.TranslateFromPhysicsSpace(Quaternion(Radian(angle), Vector3::ZAXIS)); +} + +} // namespace Dali::Toolkit::Physics::Internal diff --git a/dali-physics/internal/chipmunk-impl/chipmunk-physics-adaptor-impl.cpp b/dali-physics/internal/chipmunk-impl/chipmunk-physics-adaptor-impl.cpp new file mode 100644 index 0000000..1a4ffb9 --- /dev/null +++ b/dali-physics/internal/chipmunk-impl/chipmunk-physics-adaptor-impl.cpp @@ -0,0 +1,183 @@ +/* + * 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. + */ + +// Class Header +#include + +// External Headers +#include + +// Internal Headers +#include +#include +#include + +namespace +{ +#if defined(DEBUG_ENABLED) +Debug::Filter* gLogFilter = Debug::Filter::New(Debug::Concise, false, "LOG_PHYSICS"); +#endif + +inline cpVect ConvertVector(Dali::Vector3 vector) +{ + return cpv(vector.x, vector.y); +} + +} // namespace + +namespace Dali::Toolkit::Physics::Internal +{ +PhysicsAdaptorPtr CreateNewPhysicsAdaptor(const Dali::Matrix& transform, Uint16Pair worldSize) +{ + PhysicsAdaptorPtr adaptor(new ChipmunkPhysicsAdaptor()); + adaptor->Initialize(transform, worldSize); + return adaptor; +} + +ChipmunkPhysicsAdaptor::ChipmunkPhysicsAdaptor() +: PhysicsAdaptor() +{ +} + +ChipmunkPhysicsAdaptor::~ChipmunkPhysicsAdaptor() +{ + // @todo Ensure physics bodies don't leak +} + +void ChipmunkPhysicsAdaptor::OnInitialize(const Dali::Matrix& transform, Uint16Pair worldSize) +{ + mTransform = transform; + mInverseTransform = transform; + mInverseTransform.Invert(); + mSize = worldSize; + + mPhysicsWorld = ChipmunkPhysicsWorld::New(mRootActor, + Dali::MakeCallback(mSlotDelegate.GetSlot(), + &PhysicsAdaptor::OnUpdateActors)); +} + +Layer ChipmunkPhysicsAdaptor::CreateDebugLayer(Dali::Window window) +{ + return Layer(); +} + +void ChipmunkPhysicsAdaptor::SetTransformAndSize(const Dali::Matrix& transform, Uint16Pair worldSize) +{ + mTransform = transform; + mInverseTransform = transform; + mInverseTransform.Invert(); + mSize = worldSize; + + GetRootActor()[Actor::Property::SIZE] = Vector3(worldSize.GetWidth(), worldSize.GetHeight(), 0); +} + +PhysicsActorPtr ChipmunkPhysicsAdaptor::AddActorBody(Dali::Actor actor, Dali::Any body) +{ + uint32_t id = static_cast(actor.GetProperty(Actor::Property::ID)); + cpBody* cBody = body.Get(); + cpBodySetUserData(cBody, this); + + mPhysicsActors.insert(std::make_pair(id, PhysicsActor::New(actor, body, *this))); + actor[Actor::Property::PARENT_ORIGIN] = Dali::ParentOrigin::CENTER; + actor[Actor::Property::ANCHOR_POINT] = Dali::AnchorPoint::CENTER; + mRootActor.Add(actor); + return mPhysicsActors.at(id); +} + +void ChipmunkPhysicsAdaptor::RemoveActorBody(PhysicsActor& physicsActor) +{ + auto iter = mPhysicsActors.find(physicsActor.GetId()); + if(iter != mPhysicsActors.end()) + { + mPhysicsActors.erase(iter); + } + Dali::Actor actor = mRootActor.FindChildById(physicsActor.GetId()); + if(actor) + { + actor.Unparent(); + } + auto body = physicsActor.GetBody(); + cpBody* cBody = body.Get(); + if(cBody) + { + cpBodySetUserData(cBody, nullptr); + } +} + +PhysicsActorPtr ChipmunkPhysicsAdaptor::GetPhysicsActor(Dali::Any body) const +{ + cpBody* cBody = body.Get(); + if(cBody) + { + return reinterpret_cast(cpBodyGetUserData(cBody)); + } + DALI_LOG_ERROR("Body not found in physics actors"); + return nullptr; +} + +// Convert a position from root actor local space to physics space +Vector3 ChipmunkPhysicsAdaptor::TranslateToPhysicsSpace(Vector3 vector) const +{ + Vector4 position = mTransform * Vector4(vector.x, vector.y, vector.z, 1.0f); + return Vector3(position); +} + +// Convert a position from physics space to root actor local space +Vector3 ChipmunkPhysicsAdaptor::TranslateFromPhysicsSpace(Vector3 vector) const +{ + Vector4 position = mInverseTransform * Vector4(vector.x, vector.y, vector.z, 1.0f); + return Vector3(position); +} + +Quaternion ChipmunkPhysicsAdaptor::TranslateToPhysicsSpace(Quaternion orientation) const +{ + // It's complicated. + return orientation; +} + +Quaternion ChipmunkPhysicsAdaptor::TranslateFromPhysicsSpace(Quaternion orientation) const +{ + // Mirroring conversion is identical in both transforms + return TranslateToPhysicsSpace(orientation); +} + +// Convert a vector from dali space to physics space +Vector3 ChipmunkPhysicsAdaptor::ConvertVectorToPhysicsSpace(Vector3 vector) const +{ + Vector4 otherVector(mTransform * Vector4(vector.x, vector.y, vector.z, 0.0f)); + return Vector3(otherVector); +} + +// Convert a vector from physics space to root actor local space +Vector3 ChipmunkPhysicsAdaptor::ConvertVectorFromPhysicsSpace(Vector3 vector) const +{ + Vector4 otherVector(mInverseTransform * Vector4(vector.x, vector.y, vector.z, 0.0f)); + return Vector3(otherVector); +} + +void ChipmunkPhysicsAdaptor::BuildPickingRay(Vector3 origin, Vector3 direction, Dali::Vector3& rayFromWorld, Dali::Vector3& rayToWorld) +{ + rayFromWorld = TranslateToPhysicsSpace(origin); + rayToWorld = TranslateToPhysicsSpace(origin); // rayToWorld is identical - there's no depth +} + +Vector3 ChipmunkPhysicsAdaptor::ProjectPoint(Vector3 origin, Vector3 direction, float distance) +{ + // Ignore direction & distance. + return TranslateToPhysicsSpace(origin); +} + +} // namespace Dali::Toolkit::Physics::Internal diff --git a/dali-physics/internal/chipmunk-impl/chipmunk-physics-adaptor-impl.h b/dali-physics/internal/chipmunk-impl/chipmunk-physics-adaptor-impl.h new file mode 100644 index 0000000..48715e3 --- /dev/null +++ b/dali-physics/internal/chipmunk-impl/chipmunk-physics-adaptor-impl.h @@ -0,0 +1,111 @@ +#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 adaptoried. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// External headers + +// Internal headers +#include + +namespace Dali::Toolkit::Physics::Internal +{ +class ChipmunkPhysicsAdaptor : public PhysicsAdaptor +{ +public: + ChipmunkPhysicsAdaptor(); + + /** + * A reference counted object may only be deleted by calling Unreference() + */ + ~ChipmunkPhysicsAdaptor() override; + + // Remove copy constructor and copy assignment + ChipmunkPhysicsAdaptor(const PhysicsAdaptor& handle) = delete; + ChipmunkPhysicsAdaptor& operator=(const PhysicsAdaptor& handle) = delete; + + /** + * 2nd stage initialization + */ + void OnInitialize(const Dali::Matrix& transform, Uint16Pair size) override; + + /** + * @copydoc Dali::Toolkit::Physics::PhysicsAdaptor::CreateDebugLayer + */ + Dali::Layer CreateDebugLayer(Dali::Window window) override; + + /** + * @copydoc Dali::Toolkit::Physics::PhysicsAdaptor::SetTransformAndSize + */ + void SetTransformAndSize(const Dali::Matrix& transform, Uint16Pair size) override; + + /** + * @copydoc Dali::Toolkit::Physics::PhysicsAdaptor::TranslateToPhysicsSpace + */ + Dali::Vector3 TranslateToPhysicsSpace(Dali::Vector3 vector) const override; + + /** + * @copydoc Dali::Toolkit::Physics::PhysicsAdaptor::TranslateToPhysicsSpace + */ + Dali::Quaternion TranslateToPhysicsSpace(Dali::Quaternion rotation) const override; + + /** + * @copydoc Dali::Toolkit::Physics::PhysicsAdaptor::TranslateFromPhysicsSpace + */ + Dali::Vector3 TranslateFromPhysicsSpace(Dali::Vector3 vector) const override; + + /** + * @copydoc Dali::Toolkit::Physics::PhysicsAdaptor::TranslateFromPhysicsSpace + */ + Dali::Quaternion TranslateFromPhysicsSpace(Quaternion rotation) const override; + + /** + * @copydoc Dali::Toolkit::Physics::PhysicsAdaptor::ConvertVectorToPhysicsSpace + */ + Dali::Vector3 ConvertVectorToPhysicsSpace(Dali::Vector3 vector) const override; + + /** + * @copydoc Dali::Toolkit::Physics::PhysicsAdaptor::ConvertVectorFromPhysicsSpace + */ + Dali::Vector3 ConvertVectorFromPhysicsSpace(Dali::Vector3 vector) const override; + + /** + * @copydoc Dali::Toolkit::Physics::PhysicsAdaptor::AddActorBody + */ + PhysicsActorPtr AddActorBody(Dali::Actor actor, Dali::Any body) override; + + /** + * @copydoc Dali::Toolkit::Physics::PhysicsAdaptor::RemoveActorBody + */ + void RemoveActorBody(PhysicsActor& physicsActor) override; + + /** + * @copydoc Dali::Toolkit::Physics::PhysicsAdaptor::GetPhysicsActor + */ + PhysicsActorPtr GetPhysicsActor(Dali::Any body) const override; + + /** + * @copydoc Dali::Toolkit::Physics::PhysicsAdaptor::BuildPickingRay + */ + void BuildPickingRay(Dali::Vector3 origin, Dali::Vector3 direction, Dali::Vector3& rayFromWorld, Dali::Vector3& rayToWorld) override; + + /** + * @copydoc Dali::Toolkit::Physics::PhysicsAdaptor::ProjectPoint + */ + Dali::Vector3 ProjectPoint(Dali::Vector3 origin, Dali::Vector3 direction, float distance) override; +}; + +} // namespace Dali::Toolkit::Physics::Internal diff --git a/dali-physics/internal/chipmunk-impl/chipmunk-physics-world-impl.cpp b/dali-physics/internal/chipmunk-impl/chipmunk-physics-world-impl.cpp new file mode 100644 index 0000000..6157780 --- /dev/null +++ b/dali-physics/internal/chipmunk-impl/chipmunk-physics-world-impl.cpp @@ -0,0 +1,148 @@ +/* + * 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. + */ + +// Class Header +#include + +// External Headers + +// Internal Headers +#include +#include +#include + +namespace +{ +#define GRABBABLE_MASK_BIT (1u << 31) +cpShapeFilter GRAB_FILTER = {CP_NO_GROUP, GRABBABLE_MASK_BIT, GRABBABLE_MASK_BIT}; + +inline cpVect ConvertVector(Dali::Vector3 vector) +{ + return cpv(vector.x, vector.y); +} + +static void ShapeFreeWrap(cpSpace* space, cpShape* shape, void* unused) +{ + cpSpaceRemoveShape(space, shape); + cpShapeFree(shape); +} + +static void PostShapeFree(cpShape* shape, cpSpace* space) +{ + cpSpaceAddPostStepCallback(space, (cpPostStepFunc)ShapeFreeWrap, shape, NULL); +} + +static void ConstraintFreeWrap(cpSpace* space, cpConstraint* constraint, void* unused) +{ + cpSpaceRemoveConstraint(space, constraint); + cpConstraintFree(constraint); +} + +static void PostConstraintFree(cpConstraint* constraint, cpSpace* space) +{ + cpSpaceAddPostStepCallback(space, (cpPostStepFunc)ConstraintFreeWrap, constraint, NULL); +} + +static void BodyFreeWrap(cpSpace* space, cpBody* body, void* unused) +{ + cpSpaceRemoveBody(space, body); + cpBodyFree(body); +} + +static void PostBodyFree(cpBody* body, cpSpace* space) +{ + cpSpaceAddPostStepCallback(space, (cpPostStepFunc)BodyFreeWrap, body, NULL); +} +} // namespace + +namespace Dali::Toolkit::Physics::Internal +{ +std::unique_ptr ChipmunkPhysicsWorld::New(Dali::Actor rootActor, Dali::CallbackBase* updateCallback) +{ + std::unique_ptr world = std::make_unique(rootActor, updateCallback); + world->Initialize(); + return world; +} + +ChipmunkPhysicsWorld::ChipmunkPhysicsWorld(Dali::Actor rootActor, Dali::CallbackBase* updateCallback) +: PhysicsWorld(rootActor, updateCallback) +{ +} + +void ChipmunkPhysicsWorld::OnInitialize(/*void* dynamicsWorld*/) +{ + // @todo Should enable developer to optionally supply their own created cpSpace. + mSpace = cpSpaceNew(); + cpSpaceSetIterations(mSpace, 30); + cpSpaceSetSleepTimeThreshold(mSpace, 0.5f); + cpSpaceSetGravity(mSpace, cpv(0, -200)); +} + +ChipmunkPhysicsWorld::~ChipmunkPhysicsWorld() +{ + Dali::Mutex::ScopedLock lock(mMutex); + if(mSpace) + { + cpSpaceEachShape(mSpace, (cpSpaceShapeIteratorFunc)PostShapeFree, mSpace); + cpSpaceEachConstraint(mSpace, (cpSpaceConstraintIteratorFunc)PostConstraintFree, mSpace); + cpSpaceEachBody(mSpace, (cpSpaceBodyIteratorFunc)PostBodyFree, mSpace); + cpSpaceFree(mSpace); + mSpace = nullptr; + } +} + +Dali::Any ChipmunkPhysicsWorld::GetNative() +{ + return mSpace; +} + +void ChipmunkPhysicsWorld::Integrate(float timestep) +{ + if(mPhysicsIntegrateState == Physics::PhysicsAdaptor::IntegrationState::ON) + { + cpSpaceStep(mSpace, timestep); + } +} + +Dali::Any ChipmunkPhysicsWorld::HitTest(Dali::Vector3 rayFromWorld, Dali::Vector3 rayToWorld, Dali::Vector3& localPivot, float& distanceFromCamera) +{ + cpVect spacePosition = cpv(rayFromWorld.x, rayFromWorld.y); + cpFloat radius = 5.0f; + cpPointQueryInfo info = {0}; + cpShape* shape = cpSpacePointQueryNearest(mSpace, spacePosition, radius, GRAB_FILTER, &info); + cpBody* hitBody{nullptr}; + + if(shape && cpBodyGetMass(cpShapeGetBody(shape)) < INFINITY) + { + // Use the closest point on the surface if the click is outside the shape. + cpVect nearest = (info.distance > 0.0f ? info.point : spacePosition); + hitBody = cpShapeGetBody(shape); + cpVect local = cpBodyWorldToLocal(hitBody, nearest); + localPivot.x = local.x; + localPivot.y = local.y; + localPivot.z = 0.0; + } + + Dali::Any bodyPtr; + // Only set non-null ptr into bodyPtr, leave empty if null. + if(hitBody) + { + bodyPtr = hitBody; + } + return bodyPtr; +} + +} // namespace Dali::Toolkit::Physics::Internal diff --git a/dali-physics/internal/chipmunk-impl/chipmunk-physics-world-impl.h b/dali-physics/internal/chipmunk-impl/chipmunk-physics-world-impl.h new file mode 100644 index 0000000..4f7b2d6 --- /dev/null +++ b/dali-physics/internal/chipmunk-impl/chipmunk-physics-world-impl.h @@ -0,0 +1,46 @@ +#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 ChipmunkPhysicsWorld : public PhysicsWorld +{ +public: + static std::unique_ptr New(Dali::Actor rootActor, Dali::CallbackBase* updateCallback); + + ChipmunkPhysicsWorld(Dali::Actor rootActor, Dali::CallbackBase* updateCallback); + ~ChipmunkPhysicsWorld() override; + + void OnInitialize(/*void* dynamicsWorld*/) override; + + Dali::Any GetNative() override; + + void Integrate(float timestep) override; + + Dali::Any HitTest(Dali::Vector3 rayFromWorld, Dali::Vector3 rayToWorld, Dali::Vector3& localPivot, float& distanceFromCamera) override; + +private: + cpSpace* mSpace; +}; + +} //namespace Dali::Toolkit::Physics::Internal diff --git a/dali-physics/internal/file.list b/dali-physics/internal/file.list index 9b2cf6e..87c7cb2 100644 --- a/dali-physics/internal/file.list +++ b/dali-physics/internal/file.list @@ -1,8 +1,20 @@ -set(physics3d_internal_dir "${physics_dir}/internal") +set(physics_internal_dir ${physics_dir}/internal) +set(physics2d_internal_dir ${physics_internal_dir}/chipmunk-impl) +set(physics3d_internal_dir ${physics_internal_dir}/bullet-impl) -set(physics3d_src_files ${physics3d_src_files} - ${physics3d_internal_dir}/physics-actor-impl.cpp - ${physics3d_internal_dir}/physics-adaptor-impl.cpp - ${physics3d_internal_dir}/physics-debug-renderer.cpp - ${physics3d_internal_dir}/physics-world-impl.cpp +set(physics2d_src_files ${physics_src_files} + ${physics2d_internal_dir}/chipmunk-physics-actor-impl.cpp + ${physics2d_internal_dir}/chipmunk-physics-adaptor-impl.cpp + ${physics2d_internal_dir}/chipmunk-physics-world-impl.cpp + ${physics_internal_dir}/physics-adaptor-impl.cpp + ${physics_internal_dir}/physics-world-impl.cpp +) + +set(physics3d_src_files ${physics_src_files} + ${physics3d_internal_dir}/bullet-physics-actor-impl.cpp + ${physics3d_internal_dir}/bullet-physics-adaptor-impl.cpp + ${physics3d_internal_dir}/bullet-physics-debug-renderer.cpp + ${physics3d_internal_dir}/bullet-physics-world-impl.cpp + ${physics_internal_dir}/physics-adaptor-impl.cpp + ${physics_internal_dir}/physics-world-impl.cpp ) diff --git a/dali-physics/internal/physics-actor-impl.h b/dali-physics/internal/physics-actor-impl.h index 583bbfa..6aa2624 100644 --- a/dali-physics/internal/physics-actor-impl.h +++ b/dali-physics/internal/physics-actor-impl.h @@ -35,7 +35,7 @@ class PhysicsAdaptor; using PhysicsActorPtr = Dali::IntrusivePtr; -class DALI_TOOLKIT_API PhysicsActor : public Dali::BaseObject +class PhysicsActor : public Dali::BaseObject { public: PhysicsActor(Dali::Actor actor, Dali::Any body, PhysicsAdaptor& adaptor); diff --git a/dali-physics/internal/physics-adaptor-impl.cpp b/dali-physics/internal/physics-adaptor-impl.cpp index dd20c0b..09b3408 100644 --- a/dali-physics/internal/physics-adaptor-impl.cpp +++ b/dali-physics/internal/physics-adaptor-impl.cpp @@ -18,8 +18,6 @@ #include // External Headers -#include -#include #include #include @@ -36,59 +34,10 @@ namespace Debug::Filter* gLogFilter = Debug::Filter::New(Debug::Concise, false, "LOG_PHYSICS"); #endif -inline btVector3 ConvertVector(Dali::Vector3 vector) -{ - return btVector3(vector.x, vector.y, vector.z); -} - } // namespace -namespace Dali::Toolkit::Physics -{ -struct PhysicsAdaptor::ScopedPhysicsAccessor::Impl -{ - Impl(Internal::PhysicsWorld& world) - : mLock(world.GetMutex()), - mPhysicsWorld(world) - { - } - Impl(Impl&) = delete; - const Impl& operator=(const Impl&) = delete; - - Dali::Mutex::ScopedLock mLock; - Internal::PhysicsWorld& mPhysicsWorld; - friend Internal::PhysicsAdaptor; -}; - -PhysicsAdaptor::ScopedPhysicsAccessor::ScopedPhysicsAccessor(Internal::PhysicsWorld& world) -: mImpl(new Impl(world)) -{ -} -PhysicsAdaptor::ScopedPhysicsAccessor::~ScopedPhysicsAccessor() -{ - delete mImpl; -} - -Dali::Any PhysicsAdaptor::ScopedPhysicsAccessor::GetNative() -{ - return mImpl->mPhysicsWorld.GetNative(); -} - -Dali::Any PhysicsAdaptor::ScopedPhysicsAccessor::HitTest( - Dali::Vector3 rayFromWorld, Dali::Vector3 rayToWorld, Dali::Vector3& localPivot, float& distanceFromCamera) +namespace Dali::Toolkit::Physics::Internal { - return mImpl->mPhysicsWorld.HitTest(rayFromWorld, rayToWorld, localPivot, distanceFromCamera); -} - -namespace Internal -{ -PhysicsAdaptorPtr PhysicsAdaptor::New(const Dali::Matrix& transform, Uint16Pair worldSize) -{ - PhysicsAdaptorPtr adaptor(new PhysicsAdaptor()); - adaptor->Initialize(transform, worldSize); - return adaptor; -} - PhysicsAdaptor::PhysicsAdaptor() : mSlotDelegate(this) { @@ -96,28 +45,22 @@ PhysicsAdaptor::PhysicsAdaptor() PhysicsAdaptor::~PhysicsAdaptor() { - // @todo Ensure physics bodies don't leak } void PhysicsAdaptor::Initialize(const Dali::Matrix& transform, Uint16Pair worldSize) { - mTransform = transform; - mInverseTransform = transform; - mInverseTransform.Invert(); - mSize = worldSize; - // Create an actor that can handle mouse events. // @todo Enable this to be fully configured / provided mRootActor = Layer::New(); + mRootActor[Actor::Property::NAME] = "PhysicsRootLayer"; mRootActor[Layer::Property::BEHAVIOR] = Layer::LAYER_3D; mRootActor[Layer::Property::DEPTH_TEST] = true; - mRootActor[Actor::Property::SIZE] = Vector2(mSize.GetWidth(), mSize.GetHeight()); + mRootActor[Actor::Property::SIZE] = Vector2(worldSize.GetWidth(), worldSize.GetHeight()); mRootActor[Actor::Property::ANCHOR_POINT] = Dali::AnchorPoint::CENTER; mRootActor[Actor::Property::PARENT_ORIGIN] = Dali::ParentOrigin::CENTER; - mPhysicsWorld = PhysicsWorld::New(mRootActor, - Dali::MakeCallback(mSlotDelegate.GetSlot(), - &PhysicsAdaptor::OnUpdateActors)); + // Initialize derived adaptor (and world) + OnInitialize(transform, worldSize); } void PhysicsAdaptor::SetTimestep(float timestep) @@ -125,7 +68,7 @@ void PhysicsAdaptor::SetTimestep(float timestep) mPhysicsWorld->SetTimestep(timestep); } -float PhysicsAdaptor::GetTimestep() +float PhysicsAdaptor::GetTimestep() const { return mPhysicsWorld->GetTimestep(); } @@ -135,70 +78,12 @@ Physics::PhysicsAdaptor::ScopedPhysicsAccessorPtr PhysicsAdaptor::GetPhysicsAcce return std::unique_ptr(new Physics::PhysicsAdaptor::ScopedPhysicsAccessor(*mPhysicsWorld.get())); } -Layer PhysicsAdaptor::CreateDebugLayer(Dali::Window window) -{ - Layer debugLayer; - - auto renderTaskList = window.GetRenderTaskList(); - auto renderTask = renderTaskList.GetTask(0); - auto windowSize = window.GetSize(); - - debugLayer = Layer::New(); - debugLayer[Actor::Property::ANCHOR_POINT] = Dali::AnchorPoint::CENTER; - debugLayer[Actor::Property::PARENT_ORIGIN] = Dali::ParentOrigin::CENTER; - - Constraint positionConstraint = Constraint::New(debugLayer, Actor::Property::POSITION, EqualToConstraint()); - positionConstraint.AddSource(Source(mRootActor, Actor::Property::POSITION)); - positionConstraint.Apply(); - Constraint sizeConstraint = Constraint::New(debugLayer, Actor::Property::SIZE, EqualToConstraint()); - sizeConstraint.AddSource(Source(mRootActor, Actor::Property::SIZE)); - sizeConstraint.Apply(); - - mDebugRenderer = PhysicsDebugRenderer::New(windowSize.GetWidth(), windowSize.GetHeight(), renderTask.GetCameraActor(), this); - mDebugActor = DrawableActor::New(*(mDebugRenderer->GetCallback().get())); - mDebugActor[Actor::Property::ANCHOR_POINT] = Dali::AnchorPoint::CENTER; - mDebugActor[Actor::Property::PARENT_ORIGIN] = Dali::ParentOrigin::CENTER; - - Constraint sizeConstraint2 = Constraint::New(mDebugActor, Actor::Property::SIZE, EqualToConstraint()); - sizeConstraint2.AddSource(ParentSource(Actor::Property::SIZE)); - sizeConstraint2.Apply(); - - debugLayer.Add(mDebugActor); - - auto bulletWorld = mPhysicsWorld->GetNative().Get(); - - bulletWorld->setDebugDrawer(mDebugRenderer.get()); - mDebugRenderer->setDebugMode(btIDebugDraw::DBG_DrawWireframe | - btIDebugDraw::DBG_DrawContactPoints | - btIDebugDraw::DBG_DrawNormals); - - window.Add(debugLayer); - return debugLayer; -} - -void PhysicsAdaptor::SetTransformAndSize(const Dali::Matrix& transform, Uint16Pair worldSize) -{ - mTransform = transform; - mInverseTransform = transform; - mInverseTransform.Invert(); - mSize = worldSize; - - GetRootActor()[Actor::Property::SIZE] = Vector3(worldSize.GetWidth(), worldSize.GetHeight(), 0); - - if(mDebugRenderer) - { - Actor layer = mDebugActor.GetParent(); - layer[Actor::Property::SIZE] = Vector3(worldSize); - mDebugRenderer->UpdateWindowSize(worldSize); - } -} - void PhysicsAdaptor::SetIntegrationState(Physics::PhysicsAdaptor::IntegrationState state) { mPhysicsWorld->SetIntegrationState(state); } -Physics::PhysicsAdaptor::IntegrationState PhysicsAdaptor::GetIntegrationState() +Physics::PhysicsAdaptor::IntegrationState PhysicsAdaptor::GetIntegrationState() const { return mPhysicsWorld->GetIntegrationState(); } @@ -208,119 +93,16 @@ void PhysicsAdaptor::SetDebugState(Physics::PhysicsAdaptor::DebugState state) mPhysicsWorld->SetDebugState(state); } -Physics::PhysicsAdaptor::DebugState PhysicsAdaptor::GetDebugState() +Physics::PhysicsAdaptor::DebugState PhysicsAdaptor::GetDebugState() const { return mPhysicsWorld->GetDebugState(); } -PhysicsActorPtr PhysicsAdaptor::AddActorBody(Dali::Actor actor, Dali::Any body) -{ - uint32_t id = static_cast(actor.GetProperty(Actor::Property::ID)); - btRigidBody* btBody = body.Get(); - - btBody->setUserIndex(id); - mPhysicsActors.insert(std::make_pair(id, PhysicsActor::New(actor, body, *this))); - actor[Actor::Property::PARENT_ORIGIN] = Dali::ParentOrigin::CENTER; - actor[Actor::Property::ANCHOR_POINT] = Dali::AnchorPoint::CENTER; - mRootActor.Add(actor); - return mPhysicsActors.at(id); -} - -PhysicsActorPtr PhysicsAdaptor::GetPhysicsActor(Dali::Any body) -{ - btRigidBody* btBody = body.Get(); - if(btBody) - { - int id = btBody->getUserIndex(); - auto iter = mPhysicsActors.find(id); - if(iter != mPhysicsActors.end()) - { - return iter->second; - } - } - DALI_LOG_ERROR("Body not found in physics actors"); - return nullptr; -} - -Dali::Actor PhysicsAdaptor::GetRootActor() +Dali::Actor PhysicsAdaptor::GetRootActor() const { return mRootActor; } -// Convert a position from root actor local space to physics space -Vector3 PhysicsAdaptor::TranslateToPhysicsSpace(Vector3 vector) -{ - Vector4 position = mTransform * Vector4(vector.x, vector.y, vector.z, 1.0f); - return Vector3(position); -} - -// Convert a position from physics space to root actor local space -Vector3 PhysicsAdaptor::TranslateFromPhysicsSpace(Vector3 vector) -{ - Vector4 position = mInverseTransform * Vector4(vector.x, vector.y, vector.z, 1.0f); - return Vector3(position); -} - -Quaternion PhysicsAdaptor::TranslateToPhysicsSpace(Quaternion orientation) -{ - // Naive check for speed. Should pass scale in constructor/transform setter - - if(std::signbit(mTransform.AsFloat()[0])) // mirrored in x - { - return Quaternion(orientation.mVector.w, orientation.mVector.x, -orientation.mVector.y, -orientation.mVector.z); - } - else if(std::signbit(mTransform.AsFloat()[5])) // mirrored in y - { - return Quaternion(orientation.mVector.w, -orientation.mVector.x, orientation.mVector.y, -orientation.mVector.z); - } - else if(std::signbit(mTransform.AsFloat()[10])) // mirrored in z - { - return Quaternion(orientation.mVector.w, -orientation.mVector.x, -orientation.mVector.y, orientation.mVector.z); - } - - // No mirror, so rotation is invariant. - return orientation; -} - -Quaternion PhysicsAdaptor::TranslateFromPhysicsSpace(Quaternion orientation) -{ - // Mirroring conversion is identical in both transforms - return TranslateToPhysicsSpace(orientation); -} - -// Convert a vector from dali space to physics space -Vector3 PhysicsAdaptor::ConvertVectorToPhysicsSpace(Vector3 vector) -{ - Vector4 otherVector(mTransform * Vector4(vector.x, vector.y, vector.z, 0.0f)); - return Vector3(otherVector); -} - -// Convert a vector from physics space to root actor local space -Vector3 PhysicsAdaptor::ConvertVectorFromPhysicsSpace(Vector3 vector) -{ - Vector4 otherVector(mInverseTransform * Vector4(vector.x, vector.y, vector.z, 0.0f)); - return Vector3(otherVector); -} - -void PhysicsAdaptor::BuildPickingRay(Vector3 origin, Vector3 direction, Dali::Vector3& rayFromWorld, Dali::Vector3& rayToWorld) -{ - rayFromWorld = TranslateToPhysicsSpace(origin); - // direction from DALI touch is normalized. - // Multiply it up so that it goes through the visible world. (@todo use Space config?) - rayToWorld = TranslateToPhysicsSpace(origin + direction * 10000.0f); -} - -Vector3 PhysicsAdaptor::ProjectPoint(Vector3 origin, Vector3 direction, float distance) -{ - Vector3 rayFromWorld = TranslateToPhysicsSpace(origin); - Vector3 rayToWorld = TranslateToPhysicsSpace(origin + direction * 10000.0f); - - Vector3 dir = rayToWorld - rayFromWorld; - dir.Normalize(); - dir *= distance; // Should compute with scale? - return (rayFromWorld + dir); -} - void PhysicsAdaptor::OnUpdateActors(Dali::UpdateProxy* updateProxy) { for(auto&& actor : mPhysicsActors) @@ -343,5 +125,4 @@ void PhysicsAdaptor::CreateSyncPoint() mPhysicsWorld->CreateSyncPoint(); } -} // namespace Internal -} // namespace Dali::Toolkit::Physics +} // namespace Dali::Toolkit::Physics::Internal diff --git a/dali-physics/internal/physics-adaptor-impl.h b/dali-physics/internal/physics-adaptor-impl.h index 9c1644a..02e651a 100644 --- a/dali-physics/internal/physics-adaptor-impl.h +++ b/dali-physics/internal/physics-adaptor-impl.h @@ -24,7 +24,6 @@ // INTERNAL INCLUDES #include -#include #include #include @@ -33,8 +32,13 @@ namespace Dali::Toolkit::Physics namespace Internal { class PhysicsAdaptor; +class PhysicsDebugRenderer; + using PhysicsAdaptorPtr = IntrusivePtr; +// Declaration of factory function, implemented by derived class +PhysicsAdaptorPtr CreateNewPhysicsAdaptor(const Dali::Matrix& transform, Uint16Pair worldSize); + class PhysicsAdaptor : public BaseObject { public: @@ -49,12 +53,11 @@ public: PhysicsAdaptor(const PhysicsAdaptor& handle) = delete; PhysicsAdaptor& operator=(const PhysicsAdaptor& handle) = delete; - static PhysicsAdaptorPtr New(const Dali::Matrix& transform, Uint16Pair size); - /** * 2nd stage initialization */ - void Initialize(const Dali::Matrix& transform, Uint16Pair size); + void Initialize(const Dali::Matrix& transform, Uint16Pair size); + virtual void OnInitialize(const Dali::Matrix& transform, Uint16Pair size) = 0; /** * @copydoc Dali::Toolkit::Physics::PhysicsAdaptor::SetTimestep @@ -64,7 +67,7 @@ public: /** * @copydoc Dali::Toolkit::Physics::PhysicsAdaptor::GetTimestep */ - float GetTimestep(); + float GetTimestep() const; /** * @copydoc Dali::Toolkit::Physics::PhysicsAdaptor::GetPhysicsAccessor @@ -74,42 +77,42 @@ public: /** * @copydoc Dali::Toolkit::Physics::PhysicsAdaptor::CreateDebugLayer */ - Dali::Layer CreateDebugLayer(Dali::Window window); + virtual Dali::Layer CreateDebugLayer(Dali::Window window) = 0; /** * @copydoc Dali::Toolkit::Physics::PhysicsAdaptor::TranslateToPhysicsSpace */ - Dali::Vector3 TranslateToPhysicsSpace(Dali::Vector3 vector); + virtual Dali::Vector3 TranslateToPhysicsSpace(Dali::Vector3 vector) const = 0; /** * @copydoc Dali::Toolkit::Physics::PhysicsAdaptor::TranslateToPhysicsSpace */ - Dali::Quaternion TranslateToPhysicsSpace(Dali::Quaternion rotation); + virtual Dali::Quaternion TranslateToPhysicsSpace(Dali::Quaternion rotation) const = 0; /** * @copydoc Dali::Toolkit::Physics::PhysicsAdaptor::TranslateFromPhysicsSpace */ - Dali::Vector3 TranslateFromPhysicsSpace(Dali::Vector3 vector); + virtual Dali::Vector3 TranslateFromPhysicsSpace(Dali::Vector3 vector) const = 0; /** * @copydoc Dali::Toolkit::Physics::PhysicsAdaptor::TranslateFromPhysicsSpace */ - Dali::Quaternion TranslateFromPhysicsSpace(Quaternion rotation); + virtual Dali::Quaternion TranslateFromPhysicsSpace(Quaternion rotation) const = 0; /** * @copydoc Dali::Toolkit::Physics::PhysicsAdaptor::ConvertVectorToPhysicsSpace */ - Dali::Vector3 ConvertVectorToPhysicsSpace(Dali::Vector3 vector); + virtual Dali::Vector3 ConvertVectorToPhysicsSpace(Dali::Vector3 vector) const = 0; /** * @copydoc Dali::Toolkit::Physics::PhysicsAdaptor::ConvertVectorFromPhysicsSpace */ - Dali::Vector3 ConvertVectorFromPhysicsSpace(Dali::Vector3 vector); + virtual Dali::Vector3 ConvertVectorFromPhysicsSpace(Dali::Vector3 vector) const = 0; /** * @copydoc Dali::Toolkit::Physics::PhysicsAdaptor::SetTransformAndSize */ - void SetTransformAndSize(const Dali::Matrix& transform, Uint16Pair size); + virtual void SetTransformAndSize(const Dali::Matrix& transform, Uint16Pair size) = 0; /** * @copydoc Dali::Toolkit::Physics::PhysicsAdaptor::SetIntegrationState @@ -119,7 +122,7 @@ public: /** * @copydoc Dali::Toolkit::Physics::PhysicsAdaptor::GetIntegrationState */ - Physics::PhysicsAdaptor::IntegrationState GetIntegrationState(); + Physics::PhysicsAdaptor::IntegrationState GetIntegrationState() const; /** * @copydoc Dali::Toolkit::Physics::PhysicsAdaptor::SetDebugState @@ -129,32 +132,37 @@ public: /** * @copydoc Dali::Toolkit::Physics::PhysicsAdaptor::GetDebugState */ - Physics::PhysicsAdaptor::DebugState GetDebugState(); + Physics::PhysicsAdaptor::DebugState GetDebugState() const; /** * @copydoc Dali::Toolkit::Physics::PhysicsAdaptor::AddActorBody */ - PhysicsActorPtr AddActorBody(Dali::Actor actor, Dali::Any body); + virtual PhysicsActorPtr AddActorBody(Dali::Actor actor, Dali::Any body) = 0; + + /** + * @copydoc Dali::Toolkit::Physics::PhysicsAdaptor::RemoveActorBody + */ + virtual void RemoveActorBody(PhysicsActor& physicsActor) = 0; /** * @copydoc Dali::Toolkit::Physics::PhysicsAdaptor::GetPhysicsActor */ - PhysicsActorPtr GetPhysicsActor(Dali::Any body); + virtual PhysicsActorPtr GetPhysicsActor(Dali::Any body) const = 0; /** * @copydoc Dali::Toolkit::Physics::PhysicsAdaptor::GetRootActor */ - Dali::Actor GetRootActor(); + Dali::Actor GetRootActor() const; /** * @copydoc Dali::Toolkit::Physics::PhysicsAdaptor::BuildPickingRay */ - void BuildPickingRay(Dali::Vector3 origin, Dali::Vector3 direction, Dali::Vector3& rayFromWorld, Dali::Vector3& rayToWorld); + virtual void BuildPickingRay(Dali::Vector3 origin, Dali::Vector3 direction, Dali::Vector3& rayFromWorld, Dali::Vector3& rayToWorld) = 0; /** * @copydoc Dali::Toolkit::Physics::PhysicsAdaptor::ProjectPoint */ - Dali::Vector3 ProjectPoint(Dali::Vector3 origin, Dali::Vector3 direction, float distance); + virtual Dali::Vector3 ProjectPoint(Dali::Vector3 origin, Dali::Vector3 direction, float distance) = 0; /** * @copydoc Dali::Toolkit::Physics::PhysicsAdaptor::Queue @@ -166,24 +174,21 @@ public: */ void CreateSyncPoint(); -private: /** * Handle the update of all of the known bound actors */ void OnUpdateActors(Dali::UpdateProxy* updateProxy); -private: +protected: std::unique_ptr mPhysicsWorld; std::unordered_map mPhysicsActors; Dali::Actor mRootActor; - Dali::Actor mDebugActor; Dali::Matrix mTransform; Dali::Matrix mInverseTransform; Dali::Uint16Pair mSize; - std::unique_ptr mDebugRenderer; - Dali::SlotDelegate mSlotDelegate; + Dali::SlotDelegate mSlotDelegate; }; } //namespace Internal diff --git a/dali-physics/internal/physics-world-impl.cpp b/dali-physics/internal/physics-world-impl.cpp index d8cd6af..cd43633 100644 --- a/dali-physics/internal/physics-world-impl.cpp +++ b/dali-physics/internal/physics-world-impl.cpp @@ -18,12 +18,6 @@ #include // External Headers -#include -#include -#include -#include -#include -#include // Internal Headers #include @@ -62,31 +56,16 @@ private: // Member variables PhysicsWorld& mPhysicsWorld; }; -using NativeWorld = btDiscreteDynamicsWorld*; - -std::unique_ptr PhysicsWorld::New(Dali::Actor rootActor, Dali::CallbackBase* updateCallback) -{ - std::unique_ptr world = std::make_unique(rootActor, updateCallback); - world->Initialize(); - return world; -} - PhysicsWorld::PhysicsWorld(Dali::Actor rootActor, Dali::CallbackBase* updateCallback) : mUpdateCallback(updateCallback), mRootActor(rootActor) { - Initialize(); } -void PhysicsWorld::Initialize(/*void* dynamicsWorld*/) +void PhysicsWorld::Initialize() { - // @todo Should enable developer to supply their own created DynamicsWorld. - - mCollisionConfiguration = new btDefaultCollisionConfiguration(); - mDispatcher = new btCollisionDispatcher(mCollisionConfiguration); - mBroadphase = new btDbvtBroadphase(); - mSolver = new btSequentialImpulseConstraintSolver; - mDynamicsWorld = new btDiscreteDynamicsWorld(mDispatcher, mBroadphase, mSolver, mCollisionConfiguration); + // Call derived class's initializer + OnInitialize(); // Automatically start the frame callback. This means everything should // be accessed with a mutex lock, which is automatically locked when @@ -96,51 +75,12 @@ void PhysicsWorld::Initialize(/*void* dynamicsWorld*/) Dali::Stage::GetCurrent().KeepRendering(30); // @todo Remove! } -Dali::Any PhysicsWorld::GetNative() -{ - return mDynamicsWorld; -} - PhysicsWorld::~PhysicsWorld() { - Dali::DevelStage::RemoveFrameCallback(Dali::Stage::GetCurrent(), *mFrameCallback); - - Dali::Mutex::ScopedLock lock(mMutex); + // Derived class's destructor should clean down physics objects under mutex lock + // On completion, can remove the callback. - if(mDynamicsWorld) - { - int i; - for(i = mDynamicsWorld->getNumConstraints() - 1; i >= 0; i--) - { - mDynamicsWorld->removeConstraint(mDynamicsWorld->getConstraint(i)); - } - for(i = mDynamicsWorld->getNumCollisionObjects() - 1; i >= 0; i--) - { - btCollisionObject* obj = mDynamicsWorld->getCollisionObjectArray()[i]; - btRigidBody* body = btRigidBody::upcast(obj); - if(body && body->getMotionState()) - { - delete body->getMotionState(); - } - mDynamicsWorld->removeCollisionObject(obj); - delete obj; - } - } - - /* - for (int j = 0; j < m_collisionShapes.size(); j++) - { - btCollisionShape* shape = mCollisionShapes[j]; - delete shape; - } - mCollisionShapes.clear(); - */ - - delete mDynamicsWorld; - delete mSolver; - delete mBroadphase; - delete mDispatcher; - delete mCollisionConfiguration; + Dali::DevelStage::RemoveFrameCallback(Dali::Stage::GetCurrent(), *mFrameCallback); } Dali::Mutex& PhysicsWorld::GetMutex() @@ -184,18 +124,6 @@ bool PhysicsWorld::OnUpdate(Dali::UpdateProxy& updateProxy, float elapsedSeconds return true; } -void PhysicsWorld::Integrate(float timestep) -{ - if(mPhysicsIntegrateState == Physics::PhysicsAdaptor::IntegrationState::ON) - { - mDynamicsWorld->stepSimulation(timestep); - } - if(mDynamicsWorld->getDebugDrawer() && mPhysicsDebugState == Physics::PhysicsAdaptor::DebugState::ON) - { - mDynamicsWorld->debugDrawWorld(); - } -} - void PhysicsWorld::SetTimestep(float timeStep) { mPhysicsTimeStep = timeStep; @@ -224,48 +152,6 @@ void PhysicsWorld::CreateSyncPoint() mNotifySyncPoint = Dali::DevelStage::NotifyFrameCallback(Dali::Stage::GetCurrent(), *mFrameCallback); } -inline btVector3 ConvertVector(Dali::Vector3 vector) -{ - return btVector3(vector.x, vector.y, vector.z); -} - -Dali::Any PhysicsWorld::HitTest(Dali::Vector3 rayFromWorld, Dali::Vector3 rayToWorld, Dali::Vector3& localPivot, float& distanceFromCamera) -{ - btRigidBody* hitBody{nullptr}; - - btVector3 origin = ConvertVector(rayFromWorld); - btVector3 end = ConvertVector(rayToWorld); - btCollisionWorld::ClosestRayResultCallback rayResultCallback(origin, end); - rayResultCallback.m_flags |= btTriangleRaycastCallback::kF_UseGjkConvexCastRaytest; - - mDynamicsWorld->rayTest(origin, end, rayResultCallback); - if(rayResultCallback.hasHit()) - { - auto pickPos = rayResultCallback.m_hitPointWorld; - btRigidBody* body = (btRigidBody*)btRigidBody::upcast(rayResultCallback.m_collisionObject); - if(body) - { - if(!(body->isStaticObject() || body->isKinematicObject())) - { - hitBody = body; // Found a dynamic body. - distanceFromCamera = (pickPos - origin).length(); - - btVector3 pivot = body->getCenterOfMassTransform().inverse() * pickPos; - localPivot.x = pivot.x(); - localPivot.y = pivot.y(); - localPivot.z = pivot.z(); - } - } - } - Dali::Any bodyPtr; - if(hitBody) - { - bodyPtr = hitBody; - } - - return bodyPtr; -} - void PhysicsWorld::SetIntegrationState(Physics::PhysicsAdaptor::IntegrationState state) { mPhysicsIntegrateState = state; diff --git a/dali-physics/internal/physics-world-impl.h b/dali-physics/internal/physics-world-impl.h index fa6108f..cb9d543 100644 --- a/dali-physics/internal/physics-world-impl.h +++ b/dali-physics/internal/physics-world-impl.h @@ -24,7 +24,6 @@ #include -#include #include #include @@ -33,17 +32,49 @@ namespace Dali::Toolkit::Physics::Internal class PhysicsWorld; class FrameCallback; -class PhysicsWorld /* : public BaseObject */ +/** + * Abstract class that handles the update frame callback, queuing and calling + * functions before the integration step ; calling the integration step, + * and owning the mutex for the update callback. + * + * Implementing classes should also hold the physics world. + */ +class PhysicsWorld { public: + /** + * Create a new physics world. + */ static std::unique_ptr New(Dali::Actor rootActor, Dali::CallbackBase* updateCallback); + /** + * Constructor which takes the root actor and a callback from the PhysicsAdaptor + * @param[in] rootActor The root actor that physics actors will be added to + * @param[in] updateCallback A callback from the PhysicsAdaptor which updates the physics actors after the integration step + */ PhysicsWorld(Dali::Actor rootActor, Dali::CallbackBase* updateCallback); - ~PhysicsWorld(); - void Initialize(/*void* dynamicsWorld*/); + /** + * Virtual destructor. + * Note, removes the frame callback. + */ + virtual ~PhysicsWorld(); - Dali::Any GetNative(); + /** + * Initialize derived classes and creates the frame callback + */ + void Initialize(); + + /** + * Initialize the derived class + */ + virtual void OnInitialize() = 0; + + /** + * Get the native physics world / space. + * @return A pointer to the physics world / space + */ + virtual Dali::Any GetNative() = 0; /** * Set how long the integration should take. @@ -61,7 +92,6 @@ public: * Queue a function for execution in the update thread, prior to the physics integration. * Enables syncronization of DALi properties and physics controlled properties. */ - void Queue(std::function function); /** @@ -85,7 +115,7 @@ public: * @param[out] distanceFromCamera The distance of the pick point from the camera * @return Empty value if no dynamic body found, otherwise a valid ptr to the hit body. */ - Dali::Any HitTest(Dali::Vector3 rayFromWorld, Dali::Vector3 rayToWorld, Dali::Vector3& localPivot, float& distanceFromCamera); + virtual Dali::Any HitTest(Dali::Vector3 rayFromWorld, Dali::Vector3 rayToWorld, Dali::Vector3& localPivot, float& distanceFromCamera) = 0; /** * @copydoc Dali::Toolkit::Physics::PhysicsAdaptor::SetIntegrationState @@ -112,25 +142,18 @@ public: bool OnUpdate(Dali::UpdateProxy& updateProxy, float elapsedSeconds); -private: - void Integrate(float timestep); - -private: - Dali::Mutex mMutex; - - btDiscreteDynamicsWorld* mDynamicsWorld{nullptr}; - btCollisionDispatcher* mDispatcher{nullptr}; - btDefaultCollisionConfiguration* mCollisionConfiguration{nullptr}; - btBroadphaseInterface* mBroadphase{nullptr}; - btSequentialImpulseConstraintSolver* mSolver{nullptr}; +protected: + virtual void Integrate(float timestep) = 0; +protected: + Dali::Mutex mMutex; std::queue> commandQueue; Dali::UpdateProxy::NotifySyncPoint mNotifySyncPoint; Dali::CallbackBase* mUpdateCallback{nullptr}; std::unique_ptr mFrameCallback; Dali::Actor mRootActor; - float mPhysicsTimeStep{1.0 / 180.0}; + float mPhysicsTimeStep{1.0 / 180.0}; Physics::PhysicsAdaptor::IntegrationState mPhysicsIntegrateState{Physics::PhysicsAdaptor::IntegrationState::ON}; Physics::PhysicsAdaptor::DebugState mPhysicsDebugState{Physics::PhysicsAdaptor::DebugState::OFF}; }; diff --git a/dali-physics/public-api/file.list b/dali-physics/public-api/file.list index 0f454c7..6cb7384 100644 --- a/dali-physics/public-api/file.list +++ b/dali-physics/public-api/file.list @@ -1,11 +1,12 @@ -set(physics3d_public_api_dir "${physics_dir}/public-api") +set(physics_public_api_dir "${physics_dir}/public-api") -set(physics3d_src_files ${physics3d_src_files} - ${physics3d_public_api_dir}/physics-actor.cpp - ${physics3d_public_api_dir}/physics-adaptor.cpp +set(physics_src_files ${physics_src_files} + ${physics_public_api_dir}/physics-actor.cpp + ${physics_public_api_dir}/physics-adaptor.cpp + ${physics_public_api_dir}/scoped-physics-accessor.cpp ) -set(physics3d_public_api_header_files - ${physics3d_public_api_dir}/physics-actor.h - ${physics3d_public_api_dir}/physics-adaptor.h +set(physics_public_api_header_files + ${physics_public_api_dir}/physics-actor.h + ${physics_public_api_dir}/physics-adaptor.h ) diff --git a/dali-physics/public-api/physics-actor.h b/dali-physics/public-api/physics-actor.h index e4514bd..616c7b2 100644 --- a/dali-physics/public-api/physics-actor.h +++ b/dali-physics/public-api/physics-actor.h @@ -53,16 +53,59 @@ class PhysicsActor; class DALI_TOOLKIT_API PhysicsActor : public Dali::BaseHandle { public: + /** + * @brief Constructor + * + * @SINCE_2_2.43 + */ PhysicsActor(); + + /** + * @brief Destructor. + * + * @SINCE_2_2.43 + * This is non-virtual since derived Handle types must not contain data or virtual methods + */ ~PhysicsActor(); + + /** + * @brief Copy Constructor. + * + * @SINCE_2_2.43 + * @param[in] handle The handle to copy + * @note This creates a new handle, but does not create a new implementation object. + */ PhysicsActor(const PhysicsActor& handle); + + /** + * @brief Move Constructor. + * + * @SINCE_2_2.43 + * @param[in] handle A reference to the handle to move + */ PhysicsActor(PhysicsActor&& rhs) noexcept; + + /** + * @brief Assignment operator. + * + * @SINCE_2_2.43 + * @param[in] handle A reference to the handle to move + * @return a reference to this handle + */ PhysicsActor& operator=(const PhysicsActor& handle); + + /** + * @brief Move Assignment operator. + * + * @SINCE_2_2.43 + * @param[in] handle A reference to the handle to move + * @return a reference to this handle + */ PhysicsActor& operator=(PhysicsActor&& handle) noexcept; /** * New method. - * @SINCE_2.2.40 + * @SINCE_2_2.43 * * 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 @@ -87,7 +130,7 @@ public: * If handle points to an PhysicsActor object, the downcast produces valid handle. * If not, the returned handle is left uninitialized. * - * @SINCE_2.2.40 + * @SINCE_2_2.43 * @param[in] handle to an object * @return handle to a PhysicsActor object or an uninitialized handle */ @@ -95,10 +138,15 @@ public: /** * @brief Get the actor ID of the associated actor. + * + * @SINCE_2_2.43 */ uint32_t GetId() const; /** + * @brief Get the actual physics body of this object. + * + * @SINCE_2_2.43 * Using ANY wrapper to enable this interface to be used for any * types of physics bodies from either 2d or 3d physics. * @return The physics body. It can be cast to an appropriate type, @@ -112,39 +160,51 @@ public: Dali::Any GetBody() const; /** - * Queue a method to set the position on the associated physics body + * @brief Queue a method to set the position on the associated physics body * in the update thread before the next integration. + * + * @SINCE_2_2.43 * @param[in] actorPosition The position of the actor in DALi space */ void AsyncSetPhysicsPosition(Dali::Vector3 actorPosition); /** - * Queue a method to set the rotation of the associated physics body + * @brief Queue a method to set the rotation of the associated physics body * in the update thread before the next integration. + * + * @SINCE_2_2.43 * @param[in] actorRotation The orientation of the actor in DALi space */ void AsyncSetPhysicsRotation(Dali::Quaternion actorRotation); /** - * Get the current position of the physics body in Physics space. + * @brief Get the current position of the physics body in Physics space. + * + * @SINCE_2_2.43 * @return the current position of the physics body in Physics space. */ Dali::Vector3 GetPhysicsPosition() const; /** - * Get the current rotation of the physics body in Physics space. + * @brief Get the current rotation of the physics body in Physics space. + * + * @SINCE_2_2.43 * @return the current rotation of the physics body in Physics space. */ Dali::Quaternion GetPhysicsRotation() const; /** - * Get the current position of the physics body in DALi space. + * @brief Get the current position of the physics body in DALi space. + * + * @SINCE_2_2.43 * @return the current position of the physics body in DALi space. */ Dali::Vector3 GetActorPosition() const; /** - * Get the current rotation of the physics body in DALi space. + * @brief Get the current rotation of the physics body in DALi space. + * + * @SINCE_2_2.43 * @return the current rotation of the physics body in DALi space. */ Dali::Quaternion GetActorRotation() const; @@ -152,7 +212,11 @@ public: public: // Not intended for developer use /// @cond internal /** - * @note Not intented for application developers + * @brief This constructor is used by PhysicsActor::New() methods. + * + * @SINCE_2_2.43 + * @param[in] impl A pointer to a newly allocated Dali resource. + * @note Not intended for application developers */ explicit DALI_INTERNAL PhysicsActor(Internal::PhysicsActor* impl); /// @endcond diff --git a/dali-physics/public-api/physics-adaptor.cpp b/dali-physics/public-api/physics-adaptor.cpp index c5cf51f..5cc274b 100644 --- a/dali-physics/public-api/physics-adaptor.cpp +++ b/dali-physics/public-api/physics-adaptor.cpp @@ -38,7 +38,7 @@ PhysicsAdaptor& PhysicsAdaptor::operator=(PhysicsAdaptor&& handle) noexcept = de PhysicsAdaptor PhysicsAdaptor::New(const Dali::Matrix& transform, Uint16Pair size) { - Internal::PhysicsAdaptorPtr internal = Internal::PhysicsAdaptor::New(transform, size); + Internal::PhysicsAdaptorPtr internal = Internal::CreateNewPhysicsAdaptor(transform, size); return PhysicsAdaptor(internal.Get()); } @@ -52,7 +52,7 @@ void PhysicsAdaptor::SetTimestep(float timestep) GetImplementation(*this).SetTimestep(timestep); } -float PhysicsAdaptor::GetTimestep() +float PhysicsAdaptor::GetTimestep() const { return GetImplementation(*this).GetTimestep(); } @@ -67,27 +67,27 @@ Dali::Layer PhysicsAdaptor::CreateDebugLayer(Dali::Window window) return GetImplementation(*this).CreateDebugLayer(window); } -Dali::Vector3 PhysicsAdaptor::TranslateToPhysicsSpace(Dali::Vector3 vector) +Dali::Vector3 PhysicsAdaptor::TranslateToPhysicsSpace(Dali::Vector3 vector) const { return GetImplementation(*this).TranslateToPhysicsSpace(vector); } -Dali::Quaternion PhysicsAdaptor::TranslateToPhysicsSpace(Dali::Quaternion rotation) +Dali::Quaternion PhysicsAdaptor::TranslateToPhysicsSpace(Dali::Quaternion rotation) const { return GetImplementation(*this).TranslateToPhysicsSpace(rotation); } -Dali::Vector3 PhysicsAdaptor::TranslateFromPhysicsSpace(Dali::Vector3 vector) +Dali::Vector3 PhysicsAdaptor::TranslateFromPhysicsSpace(Dali::Vector3 vector) const { return GetImplementation(*this).TranslateFromPhysicsSpace(vector); } -Dali::Vector3 PhysicsAdaptor::ConvertVectorToPhysicsSpace(Dali::Vector3 vector) +Dali::Vector3 PhysicsAdaptor::ConvertVectorToPhysicsSpace(Dali::Vector3 vector) const { return GetImplementation(*this).ConvertVectorToPhysicsSpace(vector); } -Dali::Vector3 PhysicsAdaptor::ConvertVectorFromPhysicsSpace(Dali::Vector3 vector) +Dali::Vector3 PhysicsAdaptor::ConvertVectorFromPhysicsSpace(Dali::Vector3 vector) const { return GetImplementation(*this).ConvertVectorFromPhysicsSpace(vector); } @@ -102,7 +102,7 @@ void PhysicsAdaptor::SetIntegrationState(Physics::PhysicsAdaptor::IntegrationSta GetImplementation(*this).SetIntegrationState(state); } -Physics::PhysicsAdaptor::IntegrationState PhysicsAdaptor::GetIntegrationState() +Physics::PhysicsAdaptor::IntegrationState PhysicsAdaptor::GetIntegrationState() const { return GetImplementation(*this).GetIntegrationState(); } @@ -112,7 +112,7 @@ void PhysicsAdaptor::SetDebugState(Physics::PhysicsAdaptor::DebugState state) GetImplementation(*this).SetDebugState(state); } -Physics::PhysicsAdaptor::DebugState PhysicsAdaptor::GetDebugState() +Physics::PhysicsAdaptor::DebugState PhysicsAdaptor::GetDebugState() const { return GetImplementation(*this).GetDebugState(); } @@ -123,13 +123,18 @@ PhysicsActor PhysicsAdaptor::AddActorBody(Dali::Actor actor, Dali::Any body) return PhysicsActor(physicsActor.Get()); } -PhysicsActor PhysicsAdaptor::GetPhysicsActor(Dali::Any body) +void PhysicsAdaptor::RemoveActorBody(PhysicsActor physicsActor) +{ + GetImplementation(*this).RemoveActorBody(GetImplementation(physicsActor)); +} + +PhysicsActor PhysicsAdaptor::GetPhysicsActor(Dali::Any body) const { Internal::PhysicsActorPtr physicsActor = GetImplementation(*this).GetPhysicsActor(body); return PhysicsActor(physicsActor.Get()); } -Dali::Actor PhysicsAdaptor::GetRootActor() +Dali::Actor PhysicsAdaptor::GetRootActor() const { return GetImplementation(*this).GetRootActor(); } diff --git a/dali-physics/public-api/physics-adaptor.h b/dali-physics/public-api/physics-adaptor.h index e39945b..00b7e78 100644 --- a/dali-physics/public-api/physics-adaptor.h +++ b/dali-physics/public-api/physics-adaptor.h @@ -46,11 +46,18 @@ class PhysicsWorld; class DALI_TOOLKIT_API PhysicsAdaptor : public BaseHandle { public: + /** + * @brief Enumeration to turn the integration step on or off. + */ enum class IntegrationState { OFF, ON }; + + /** + * @brief Enumeration to turn the debug rendering on or off + */ enum class DebugState { OFF, @@ -58,10 +65,13 @@ public: }; /** - * 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. + * @brief Scoped accessor to the physics world. + * + * @SINCE_2_2.43 + * 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 goes out of scope, the mutex is unlocked, and the integration step * can resume. @@ -70,17 +80,21 @@ public: { public: /** - * Get a pointer to the native world. This uses DALi::Any wrapper to ensure - * that the same interface can be used for both 2d and 3d physics. It can be - * cast to the right type using the following construct: + * @brief Get a pointer to the native world. + * + * @SINCE_2_2.43 + * This uses DALi::Any wrapper to ensure that the same interface can be used + * for both 2d and 3d physics. It can be cast to the right type using the + * following construct: * auto accessor = PhysicsAdaptor.GetPhysicsAccessor(); * auto bulletWorld = accessor->GetNative().Get(); */ Dali::Any GetNative(); /** - * Hit test the physics world and return the nearest body. + * @brief Hit test the physics world and return the nearest body. * + * @SINCE_2_2.43 * @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[out] localPivot The hit point local to the body @@ -94,30 +108,81 @@ public: const ScopedPhysicsAccessor& operator=(const ScopedPhysicsAccessor&) = delete; /** - * Destructor + * @brief Destructor. + * + * On leaving scope, the mutex is unlocked and the physics integration step + * can resume. */ ~ScopedPhysicsAccessor(); private: + /** + * @brief Private constructor. + * + * It is created by the physics adaptor. + */ ScopedPhysicsAccessor(Internal::PhysicsWorld& world); friend Internal::PhysicsAdaptor; - struct Impl; + struct Impl; ///< Opaque implementation structure Impl* mImpl; }; + /** + * @brief Creates an uninitalized PhysicsAdaptor, this can be initialized with PhysicsAdaptor::New(). + * + * @SINCE_2_2.43 + * Calling member functions with an uninitialized PhysicsAdaptor handle is not allowed. + */ PhysicsAdaptor(); + + /** + * @brief Destructor + * + * This is non-virtual since derived Handle types must not contain data or virtual methods. + * @SINCE_2_2.43 + */ ~PhysicsAdaptor(); + + /** + * @brief Copy Constructor. + * + * @SINCE_2_2.43 + * @param[in] handle The handle to copy + * @note This creates a new handle, but does not create a new implementation object. + */ PhysicsAdaptor(const PhysicsAdaptor& handle); + + /** + * @brief Move Constructor. + * + * @SINCE_2_2.43 + * @param[in] handle A reference to the handle to move + */ PhysicsAdaptor(PhysicsAdaptor&& rhs) noexcept; + + /** + * @brief Assignment operator. + * + * @SINCE_2_2.43 + * @param[in] handle A reference to the handle to move + * @return a reference to this handle + */ PhysicsAdaptor& operator=(const PhysicsAdaptor& handle); - PhysicsAdaptor& operator=(PhysicsAdaptor&& handle) noexcept; /** - * Initialize the physics system. + * @brief Move Assignment operator. * - * @todo Consider allowing developer to create the physics world and pass it in here. + * @SINCE_2_2.43 + * @param[in] handle A reference to the handle to move + * @return a reference to this handle + */ + PhysicsAdaptor& operator=(PhysicsAdaptor&& handle) noexcept; + + /** + * @brief Initialize the physics system. * + * @SINCE_2_2.43 * @param[in] transform The transform matrix for DALi to Physics world space * @param[in] size The size of the layer the physics actors will be drawn in */ @@ -129,110 +194,147 @@ public: * If handle points to an PhysicsAdaptor object, the downcast produces valid handle. * If not, the returned handle is left uninitialized. * - * @SINCE_2.2.40 + * @SINCE_2_2.43 * @param[in] handle to an object * @return handle to a PhysicsAdaptor object or an uninitialized handle */ static PhysicsAdaptor DownCast(BaseHandle handle); /** - * Set how long the integration should take. + * @brief Set how long the integration should take. + * + * @SINCE_2_2.43 * @param[in] timestep The length of time that the physics integration should take. */ void SetTimestep(float timestep); /** - * Get the current physics integration timestep + * @brief Get the current physics integration timestep. + * + * @SINCE_2_2.43 * @return the current physics integration timestep */ - float GetTimestep(); + float GetTimestep() const; /** - * Returns an accessor pointer to the physics world. It automatically locks a mutex - * to prevent the integration step from running whilst the world is being modified. + * @brief Type to represent a pointer to a scoped accessor. + * + * @SINCE_2_2.43 + */ + using ScopedPhysicsAccessorPtr = std::unique_ptr; + + /** + * @brief Returns an accessor to the physics world. + * + * @SINCE_2_2.43 + * It automatically locks a mutex to prevent the integration step + * from running whilst the world is being modified. * * When the pointer goes out of scope, the mutex is unlocked and the physics world * can run again. + * @return the scoped accessor */ - using ScopedPhysicsAccessorPtr = std::unique_ptr; ScopedPhysicsAccessorPtr GetPhysicsAccessor(); /** - * Create a layer & debug renderer + * @brief Create a layer & debug renderer. + * + * @SINCE_2_2.43 * The debug renderer may utilize the debug features of the native physics * engine. * * @param[in] window The window to draw in (requires camera) + * @return The debug layer */ Dali::Layer CreateDebugLayer(Dali::Window window); /** - * Converts a point in RootActor local coords (e.g. gesture) + * @brief Converts a point in RootActor local coords (e.g. gesture) * into physics space coords. + * + * @SINCE_2_2.43 * @param vector The point to convert * @return The converted point */ - Dali::Vector3 TranslateToPhysicsSpace(Dali::Vector3 vector); + Dali::Vector3 TranslateToPhysicsSpace(Dali::Vector3 vector) const; /** - * Convert a rotation in DALi coordinate system into physics space. + * @brief Convert a rotation in DALi coordinate system into physics space. + * + * @SINCE_2_2.43 * @param[in] rotation The rotation to convert * @return the converted rotation. */ - Dali::Quaternion TranslateToPhysicsSpace(Dali::Quaternion rotation); + Dali::Quaternion TranslateToPhysicsSpace(Dali::Quaternion rotation) const; /** - * Converts a point in physics space coords. - * into RootActor local coords + * @brief Converts a point in physics space coords into RootActor local coords. + * + * @SINCE_2_2.43 * @param vector The point to convert * @return The converted point */ - Dali::Vector3 TranslateFromPhysicsSpace(Dali::Vector3 vector); + Dali::Vector3 TranslateFromPhysicsSpace(Dali::Vector3 vector) const; /** - * Convert a rotation in physics coordinate system into DALi space. + * @brief Convert a rotation in physics coordinate system into DALi space. + * + * @SINCE_2_2.43 * @param[in] rotation The rotation to convert * @return the converted rotation. */ - Dali::Quaternion TranslateFromPhysicsSpace(Dali::Quaternion rotation); + Dali::Quaternion TranslateFromPhysicsSpace(Dali::Quaternion rotation) const; /** - * Converts a vector (not a point) in DALi space into physics space. + * @brief Converts a vector (not a point) in DALi space into physics space. + * + * @SINCE_2_2.43 * @param vector The vector to convert * @return The converted vector */ - Dali::Vector3 ConvertVectorToPhysicsSpace(Dali::Vector3 vector); + Dali::Vector3 ConvertVectorToPhysicsSpace(Dali::Vector3 vector) const; /** - * Converts a vector (not a point) in physics space to DALi space + * @brief Converts a vector (not a point) in physics space to DALi space. + * + * @SINCE_2_2.43 * @param vector The vector to convert * @return The converted vector */ - Dali::Vector3 ConvertVectorFromPhysicsSpace(Dali::Vector3 vector); + Dali::Vector3 ConvertVectorFromPhysicsSpace(Dali::Vector3 vector) const; /** - * Set up the transform from world space to physics space + * @brief Set up the transform from world space to physics space. + * + * @SINCE_2_2.43 * @param[in] transform The transform matrix for DALi to Physics world space * @param[in] size The size of the layer the physics actors will be drawn in */ void SetTransformAndSize(const Dali::Matrix& transform, Uint16Pair size); /** - * Set the integration state. If it's turned on, physics will run - * during the update frame callback. + * @brief Set the integration state. + * + * @SINCE_2_2.43 + * If it's turned off, physics will be paused. * @note This is ON by default * @param[in] state the new integration state */ void SetIntegrationState(IntegrationState state); /** - * Get the integration state. + * @brief Get the integration state. + * + * @SINCE_2_2.43 * @return the new integration state */ - IntegrationState GetIntegrationState(); + IntegrationState GetIntegrationState() const; /** - * Set the debug state. If debug is turned on, use the physics engine + * @brief Set the debug state. + * + * @SINCE_2_2.43 + * If debug is turned on, use the physics engine * debug to show wireframes in a layer above the root actor. * @note This is OFF by default * @param[in] state the new debug state @@ -240,15 +342,19 @@ public: void SetDebugState(DebugState state); /** - * Get the debug state. + * @brief Get the debug state. + * + * @SINCE_2_2.43 * @return the new debug state */ - DebugState GetDebugState(); + DebugState GetDebugState() const; /** - * Add an actor / body pair. + * @brief Add an actor / body pair. * @pre It's expected that the client has added the body to the physics world. * + * The adaptor does not "take ownership" of the actor or the physics body. + * @SINCE_2_2.43 * @param[in] actor The actor used for rendering the physics object * @param[in] body The physics object * @return a handle to the actor / body pair. @@ -256,27 +362,51 @@ public: PhysicsActor AddActorBody(Dali::Actor actor, Dali::Any body); /** - * Get the physics actor associated with the given body + * @brief Remove the actor / body. + * + * This will unparent the actor from the root actor and disassociate it from + * the body. + * + * It is the responsibility of the client to remove the body from the physics world + * and destroy it at an appropriate time. Create a scoped accessor to ensure + * that the integration step isn't being run when doing so. + * + * If the root actor is holding the last reference to the actor, it will be + * destroyed automatically, otherwise it is the responsibility of the client to + * dereference the actor. + * + * @SINCE_2_2.43 + * @param[in] physicsActor The actor / body pair to remove. + */ + void RemoveActorBody(PhysicsActor physicsActor); + + /** + * @brief Get the physics actor associated with the given body. + * + * @SINCE_2_2.43 * @param[in] body The physics body * @return the associated physics actor */ - PhysicsActor GetPhysicsActor(Dali::Any body); + PhysicsActor GetPhysicsActor(Dali::Any body) const; /** - * Get the root actor (which holds all the actor/body pairs) + * @brief Get the root actor (which holds all the actor/body pairs). + * + * @SINCE_2_2.43 + * @return the root actor. */ - Dali::Actor GetRootActor(); + Dali::Actor GetRootActor() const; /** - * Convert DALi touch point into a picking ray in the physics world. + * @brief Convert DALi touch point into a picking ray in the physics world. * * These can then be used to hit test the PhysicsWorld * + * @SINCE_2_2.43 * @param[in] origin The origin in DALi world space * @param[in] direction The direction of the picking ray * @param[out] rayFromWorld The origin in physics world space - * @param[out] rayToWorld A point along the direction on the far side of the - * physics world + * @param[out] rayToWorld A point along the direction on the far side of the physics world * * Example: * OnTouched(Dali::Actor actor, Dali::TouchEvent& touch) @@ -293,10 +423,11 @@ public: void BuildPickingRay(Dali::Vector3 origin, Dali::Vector3 direction, Dali::Vector3& rayFromWorld, Dali::Vector3& rayToWorld); /** - * Project a point from the origin (in DALi space) a distance along + * @brief Project a point from the origin (in DALi space) a distance along * the direction vector (in DALi space), and return the projected * point in Physics space. * + * @SINCE_2_2.43 * @param[in] origin Origin in DALi world space * @param[in] direction Direction in DALi world space * @param[in] distance Distance along the direction vector @@ -305,7 +436,12 @@ public: Dali::Vector3 ProjectPoint(Dali::Vector3 origin, Dali::Vector3 direction, float distance); /** - * Queue a function to be executed before the physics integration in the update thread. + * @brief Queue a function to be executed before the physics integration in the update thread. + * + * @SINCE_2_2.43 + * Multiple functions can be queued up. They are executed in the update frame + * callback when the next sync point is seen, so CreateSyncPoint() should be called + * afterwards for this to be executed. * * @param[in] function to execute. This can be any method, and it can work fine with * physics bodies etc, but it must not be used with DALI event side objects, as this @@ -314,21 +450,40 @@ public: void Queue(std::function function); /** - * Create a sync point for queued functions. + * @brief Create a sync point for queued functions. * - * Ensures that any queued functions are processed after this sync - * point is seen in the Update::FrameCallback, which will be in the - * same frame as any other DALi properties set during this event - * handler invocation. + * @SINCE_2_2.43 + * Ensures that any previously queued functions are processed + * in the Update::FrameCallback during the same frame as other + * DALi properties set during this event handler invocation. + * For example, + * boxActor = Actor::New(); + * //... Create box actor renderer ... + * btRigidBodyConstructionInfo info; + * //... set construction properties + * boxBody = new btRigidBody(info); + * auto boxPhysicsActor = physicsAdaptor.AddActorBody(boxActor, boxBody); + * boxActor.SetProperty(Actor::Property::VISIBLE, true); + * boxActor.SetProperty(Actor::Property::OPACITY, 0.5f); + * physicsAdaptor.Queue([boxBody](){ boxBody->activate(true);}); + * btVector3 impulse(4, 5, 6); + * btVector3 position(); + * physicsAdaptor.Queue([boxBody](){ boxBody->applyImpulse(impulse, position);}); + * physicsAdaptor.CreateSyncPoint(); * - * @param[in] None + * Ensures that the box has both render properties and physics properties applied + * during the same frame. */ void CreateSyncPoint(); public: // Not intended for developer use /// @cond internal /** - * @note Not intented for application developers + * @brief This constructor is used by PhysicsAdaptor::New() methods. + * + * @SINCE_2_2.43 + * @param[in] impl A pointer to a newly allocated Dali resource. + * @note Not intended for application developers */ explicit DALI_INTERNAL PhysicsAdaptor(Internal::PhysicsAdaptor* impl); /// @endcond diff --git a/dali-physics/public-api/scoped-physics-accessor.cpp b/dali-physics/public-api/scoped-physics-accessor.cpp new file mode 100644 index 0000000..1f4b6e8 --- /dev/null +++ b/dali-physics/public-api/scoped-physics-accessor.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 +{ +struct PhysicsAdaptor::ScopedPhysicsAccessor::Impl +{ + Impl(Internal::PhysicsWorld& world) + : mLock(world.GetMutex()), + mPhysicsWorld(world) + { + } + Impl(Impl&) = delete; + const Impl& operator=(const Impl&) = delete; + + Dali::Mutex::ScopedLock mLock; + Internal::PhysicsWorld& mPhysicsWorld; + friend Internal::PhysicsAdaptor; +}; + +PhysicsAdaptor::ScopedPhysicsAccessor::ScopedPhysicsAccessor(Internal::PhysicsWorld& world) +: mImpl(new Impl(world)) +{ +} + +PhysicsAdaptor::ScopedPhysicsAccessor::~ScopedPhysicsAccessor() +{ + delete mImpl; +} + +Dali::Any PhysicsAdaptor::ScopedPhysicsAccessor::GetNative() +{ + return mImpl->mPhysicsWorld.GetNative(); +} + +Dali::Any PhysicsAdaptor::ScopedPhysicsAccessor::HitTest( + Dali::Vector3 rayFromWorld, Dali::Vector3 rayToWorld, Dali::Vector3& localPivot, float& distanceFromCamera) +{ + return mImpl->mPhysicsWorld.HitTest(rayFromWorld, rayToWorld, localPivot, distanceFromCamera); +} + +} // namespace Dali::Toolkit::Physics diff --git a/packaging/dali-toolkit.spec b/packaging/dali-toolkit.spec index 78611e8..431c5ce 100644 --- a/packaging/dali-toolkit.spec +++ b/packaging/dali-toolkit.spec @@ -544,15 +544,16 @@ esac %endif %defattr(-,root,root,-) %{_libdir}/libchipmunk.so* -#%{_libdir}/libdali2-physics-2d.so* +%{_libdir}/libdali2-physics-2d.so* %license LICENSE %files -n %{dali2_physics2d}-devel %defattr(-,root,root,-) %{_includedir}/dali-physics/public-api/* +%{_includedir}/dali-physics/dali-physics.h %{_includedir}/chipmunk/* -%{_libdir}/pkgconfig/dali2-physics-2d.pc %{_libdir}/pkgconfig/chipmunk2d.pc +%{_libdir}/pkgconfig/dali2-physics-2d.pc %files -n %{dali2_physics3d} %if 0%{?enable_dali_smack_rules} @@ -568,6 +569,7 @@ esac %files -n %{dali2_physics3d}-devel %defattr(-,root,root,-) %{_includedir}/dali-physics/public-api/* +%{_includedir}/dali-physics/dali-physics.h %{_includedir}/bullet/* %{_libdir}/pkgconfig/dali2-physics-3d.pc %{_libdir}/pkgconfig/bullet3.pc