Adding chipmunk implementation for physics adaptor 46/297746/6
authorDavid Steele <david.steele@samsung.com>
Tue, 22 Aug 2023 13:13:20 +0000 (14:13 +0100)
committerDavid Steele <david.steele@samsung.com>
Thu, 31 Aug 2023 18:09:45 +0000 (19:09 +0100)
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 <david.steele@samsung.com>
35 files changed:
automated-tests/src/dali-physics2d/CMakeLists.txt [new file with mode: 0644]
automated-tests/src/dali-physics2d/tct-dali-physics2d-core.cpp [moved from automated-tests/src/dali-physics/tct-dali-physics-core.cpp with 52% similarity]
automated-tests/src/dali-physics2d/utc-Dali-PhysicsActor.cpp [new file with mode: 0644]
automated-tests/src/dali-physics2d/utc-Dali-PhysicsAdaptor.cpp [new file with mode: 0644]
automated-tests/src/dali-physics3d/CMakeLists.txt [moved from automated-tests/src/dali-physics/CMakeLists.txt with 91% similarity]
automated-tests/src/dali-physics3d/tct-dali-physics3d-core.cpp [new file with mode: 0644]
automated-tests/src/dali-physics3d/utc-Dali-PhysicsActor.cpp [moved from automated-tests/src/dali-physics/utc-Dali-PhysicsActor.cpp with 95% similarity]
automated-tests/src/dali-physics3d/utc-Dali-PhysicsAdaptor.cpp [moved from automated-tests/src/dali-physics/utc-Dali-PhysicsAdaptor.cpp with 83% similarity]
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-compare-types.h
build/tizen/dali-physics/CMakeLists.txt
build/tizen/dali-physics/dali2-physics-2d.pc.in
dali-physics/internal/bullet-impl/bullet-physics-actor-impl.cpp [moved from dali-physics/internal/physics-actor-impl.cpp with 98% similarity]
dali-physics/internal/bullet-impl/bullet-physics-adaptor-impl.cpp [new file with mode: 0644]
dali-physics/internal/bullet-impl/bullet-physics-adaptor-impl.h [new file with mode: 0644]
dali-physics/internal/bullet-impl/bullet-physics-debug-renderer.cpp [moved from dali-physics/internal/physics-debug-renderer.cpp with 97% similarity]
dali-physics/internal/bullet-impl/bullet-physics-debug-renderer.h [moved from dali-physics/internal/physics-debug-renderer.h with 99% similarity]
dali-physics/internal/bullet-impl/bullet-physics-world-impl.cpp [new file with mode: 0644]
dali-physics/internal/bullet-impl/bullet-physics-world-impl.h [new file with mode: 0644]
dali-physics/internal/chipmunk-impl/chipmunk-physics-actor-impl.cpp [new file with mode: 0644]
dali-physics/internal/chipmunk-impl/chipmunk-physics-adaptor-impl.cpp [new file with mode: 0644]
dali-physics/internal/chipmunk-impl/chipmunk-physics-adaptor-impl.h [new file with mode: 0644]
dali-physics/internal/chipmunk-impl/chipmunk-physics-world-impl.cpp [new file with mode: 0644]
dali-physics/internal/chipmunk-impl/chipmunk-physics-world-impl.h [new file with mode: 0644]
dali-physics/internal/file.list
dali-physics/internal/physics-actor-impl.h
dali-physics/internal/physics-adaptor-impl.cpp
dali-physics/internal/physics-adaptor-impl.h
dali-physics/internal/physics-world-impl.cpp
dali-physics/internal/physics-world-impl.h
dali-physics/public-api/file.list
dali-physics/public-api/physics-actor.h
dali-physics/public-api/physics-adaptor.cpp
dali-physics/public-api/physics-adaptor.h
dali-physics/public-api/scoped-physics-accessor.cpp [new file with mode: 0644]
packaging/dali-toolkit.spec

diff --git a/automated-tests/src/dali-physics2d/CMakeLists.txt b/automated-tests/src/dali-physics2d/CMakeLists.txt
new file mode 100644 (file)
index 0000000..ea0f140
--- /dev/null
@@ -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}
+)
@@ -1,7 +1,8 @@
 #include <test-harness.h>
-#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 (file)
index 0000000..855d686
--- /dev/null
@@ -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 <chipmunk/chipmunk.h>
+#include <stdlib.h>
+#include <iostream>
+
+// Need to override adaptor classes for toolkit test harness, so include
+// test harness headers before dali headers.
+#include <dali-toolkit-test-suite-utils.h>
+#include <toolkit-event-thread-callback.h>
+
+#include <dali-physics/dali-physics.h>
+#include <dali-toolkit/dali-toolkit.h>
+#include <dali-toolkit/devel-api/controls/alignment/alignment.h>
+
+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<cpSpace*>();
+  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<cpSpace*>();
+  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<cpSpace*>();
+  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<cpSpace*>();
+  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<cpSpace*>();
+  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<cpSpace*>();
+  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<cpSpace*>();
+  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<cpSpace*>();
+    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<cpBody*>(), 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<cpSpace*>();
+    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<Vector3>(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<cpSpace*>();
+    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<Quaternion>(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<cpSpace*>();
+    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<Quaternion>(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<cpSpace*>();
+    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<cpSpace*>();
+    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<cpSpace*>();
+    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<cpSpace*>();
+    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 (file)
index 0000000..b6ca868
--- /dev/null
@@ -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 <stdlib.h>
+#include <iostream>
+#include <typeinfo>
+
+// Need to override adaptor classes for toolkit test harness, so include
+// test harness headers before dali headers.
+#include <dali-physics/dali-physics.h>
+#include <dali-toolkit-test-suite-utils.h>
+#include <toolkit-event-thread-callback.h>
+
+#include <dali-toolkit/devel-api/controls/alignment/alignment.h>
+#include <dali-toolkit/public-api/controls/image-view/image-view.h>
+#include <dali/devel-api/adaptor-framework/window-devel.h>
+#include <dali/devel-api/events/hit-test-algorithm.h>
+
+#include <chipmunk/chipmunk.h>
+
+using namespace Dali;
+using namespace Dali::Toolkit::Physics;
+
+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<Vector2>(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<cpSpace*>();
+
+  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<cpBody*>(), body, TEST_LOCATION);
+
+  END_TEST;
+}
+
+void removeShape(cpBody* body, cpShape* shape, void* data)
+{
+  cpSpace* space = static_cast<cpSpace*>(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<cpSpace*>();
+
+    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<cpSpace*>();
+
+    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<cpSpace*>();
+
+  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<cpSpace*>();
+    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<cpSpace*>();
+    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<cpSpace*>();
+    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;
+}
@@ -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 (file)
index 0000000..a87b21c
--- /dev/null
@@ -0,0 +1,9 @@
+#include <test-harness.h>
+
+// Must come second
+#include "tct-dali-physics3d-core.h"
+
+int main(int argc, char* const argv[])
+{
+  return TestHarness::RunTests(argc, argv, tc_array);
+}
@@ -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");
 
@@ -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<btDiscreteDynamicsWorld*>();
+
+    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<btDiscreteDynamicsWorld*>();
+
+    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<btDiscreteDynamicsWorld*>();
+
+    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");
 
index fcadd6f..a31f162 100644 (file)
@@ -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>(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>(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
index 5bf2ff8..00c482b 100644 (file)
@@ -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"
   )
 
index 75f9216..29dcbc1 100644 (file)
@@ -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}
@@ -16,6 +16,8 @@
 
 // Class Header
 #include <dali-physics/internal/physics-actor-impl.h>
+
+#include <btBulletDynamicsCommon.h>
 #include <dali-physics/internal/physics-adaptor-impl.h>
 
 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 (file)
index 0000000..9e36059
--- /dev/null
@@ -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 <dali-physics/internal/bullet-impl/bullet-physics-adaptor-impl.h>
+
+// External Headers
+#include <btBulletDynamicsCommon.h>
+#include <utility>
+
+// Internal Headers
+#include <dali-physics/internal/bullet-impl/bullet-physics-world-impl.h>
+#include <dali/dali.h>
+#include <dali/devel-api/threading/mutex.h>
+#include <dali/integration-api/debug.h>
+#include <dali/public-api/actors/drawable-actor.h>
+
+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<Vector3>(debugLayer, Actor::Property::POSITION, EqualToConstraint());
+  positionConstraint.AddSource(Source(mRootActor, Actor::Property::POSITION));
+  positionConstraint.Apply();
+  Constraint sizeConstraint = Constraint::New<Vector2>(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<Vector2>(mDebugActor, Actor::Property::SIZE, EqualToConstraint());
+  sizeConstraint2.AddSource(ParentSource(Actor::Property::SIZE));
+  sizeConstraint2.Apply();
+
+  debugLayer.Add(mDebugActor);
+
+  auto bulletWorld = mPhysicsWorld->GetNative().Get<btDiscreteDynamicsWorld*>();
+
+  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<uint32_t>(actor.GetProperty<int>(Actor::Property::ID));
+  btRigidBody* btBody = body.Get<btRigidBody*>();
+
+  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<btRigidBody*>();
+  if(btBody)
+  {
+    btBody->setUserIndex(-1);
+  }
+}
+
+PhysicsActorPtr BulletPhysicsAdaptor::GetPhysicsActor(Dali::Any body) const
+{
+  btRigidBody* btBody = body.Get<btRigidBody*>();
+  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 (file)
index 0000000..3c9001a
--- /dev/null
@@ -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 <dali-physics/internal/bullet-impl/bullet-physics-debug-renderer.h>
+#include <dali-physics/internal/physics-adaptor-impl.h>
+
+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<PhysicsDebugRenderer> mDebugRenderer;
+};
+
+} // namespace Dali::Toolkit::Physics::Internal
  * limitations under the License.
  */
 
-#include "physics-debug-renderer.h"
+// Class header
+#include <dali-physics/internal/bullet-impl/bullet-physics-debug-renderer.h>
 
+// External Includes
 #include <dali/dali.h>
-#include "physics-adaptor-impl.h"
+
+// Internal Includes
+#include <dali-physics/internal/physics-adaptor-impl.h>
 
 using Dali::Degree;
 using Dali::Matrix;
@@ -16,6 +16,7 @@
  * limitations under the License.
  */
 
+// External includes
 #include <GLES3/gl3.h>
 #include <LinearMath/btIDebugDraw.h>
 #include <dali/dali.h>
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 (file)
index 0000000..79d97de
--- /dev/null
@@ -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 <dali-physics/internal/bullet-impl/bullet-physics-world-impl.h>
+
+// External Headers
+#include <BulletCollision/NarrowPhaseCollision/btRaycastCallback.h>
+#include <btBulletCollisionCommon.h>
+#include <memory>
+
+// Internal Headers
+#include <dali/dali.h>
+#include <dali/devel-api/common/stage-devel.h>
+#include <dali/devel-api/update/frame-callback-interface.h>
+
+namespace Dali::Toolkit::Physics::Internal
+{
+std::unique_ptr<PhysicsWorld> BulletPhysicsWorld::New(Dali::Actor rootActor, Dali::CallbackBase* updateCallback)
+{
+  std::unique_ptr<BulletPhysicsWorld> world = std::make_unique<BulletPhysicsWorld>(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 (file)
index 0000000..2a5ff55
--- /dev/null
@@ -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 <dali/dali.h>
+#include <dali/devel-api/threading/mutex.h>
+#include <dali/devel-api/update/frame-callback-interface.h>
+#include <dali/devel-api/update/update-proxy.h>
+
+#include <dali-physics/internal/physics-world-impl.h>
+#include <dali-physics/public-api/physics-adaptor.h>
+
+#include <btBulletDynamicsCommon.h>
+
+namespace Dali::Toolkit::Physics::Internal
+{
+class PhysicsWorld;
+class FrameCallback;
+
+class BulletPhysicsWorld : public PhysicsWorld
+{
+public:
+  static std::unique_ptr<PhysicsWorld> 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 (file)
index 0000000..eee9cd4
--- /dev/null
@@ -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 <dali-physics/internal/physics-actor-impl.h>
+#include <dali-physics/internal/physics-adaptor-impl.h>
+
+#include <chipmunk/chipmunk.h>
+
+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<int>(Dali::Actor::Property::ID)),
+  mBody(body)
+{
+}
+
+PhysicsActor::~PhysicsActor() = default;
+
+void PhysicsActor::Initialize(void)
+{
+  cpBodySetUserData(mBody.Get<cpBody*>(), this);
+
+  // RegisterObject?
+}
+
+void PhysicsActor::AsyncSetPhysicsPosition(Dali::Vector3 actorPosition)
+{
+  // Queue task
+  cpBody* body = mBody.Get<cpBody*>();
+  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<cpBody*>();
+  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<cpBody*>();
+  return toVec3(cpBodyGetPosition(body));
+}
+
+Dali::Quaternion PhysicsActor::GetPhysicsRotation() const
+{
+  cpBody* body  = mBody.Get<cpBody*>();
+  cpFloat angle = cpBodyGetAngle(body);
+  return Quaternion(Radian(angle), Vector3::ZAXIS);
+}
+
+Dali::Vector3 PhysicsActor::GetActorPosition() const
+{
+  cpBody* body       = mBody.Get<cpBody*>();
+  cpVect  cpPosition = cpBodyGetPosition(body);
+  return mAdaptor.TranslateFromPhysicsSpace(Vector3(cpPosition.x, cpPosition.y, 0.0f));
+}
+
+Dali::Quaternion PhysicsActor::GetActorRotation() const
+{
+  cpBody* body  = mBody.Get<cpBody*>();
+  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 (file)
index 0000000..1a4ffb9
--- /dev/null
@@ -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 <dali-physics/internal/chipmunk-impl/chipmunk-physics-adaptor-impl.h>
+
+// External Headers
+#include <utility>
+
+// Internal Headers
+#include <dali-physics/internal/chipmunk-impl/chipmunk-physics-world-impl.h>
+#include <dali/dali.h>
+#include <dali/integration-api/debug.h>
+
+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<uint32_t>(actor.GetProperty<int>(Actor::Property::ID));
+  cpBody*  cBody = body.Get<cpBody*>();
+  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<cpBody*>();
+  if(cBody)
+  {
+    cpBodySetUserData(cBody, nullptr);
+  }
+}
+
+PhysicsActorPtr ChipmunkPhysicsAdaptor::GetPhysicsActor(Dali::Any body) const
+{
+  cpBody* cBody = body.Get<cpBody*>();
+  if(cBody)
+  {
+    return reinterpret_cast<PhysicsActor*>(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 (file)
index 0000000..48715e3
--- /dev/null
@@ -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 <dali-physics/internal/physics-adaptor-impl.h>
+
+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 (file)
index 0000000..6157780
--- /dev/null
@@ -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 <dali-physics/internal/chipmunk-impl/chipmunk-physics-world-impl.h>
+
+// External Headers
+
+// Internal Headers
+#include <dali/dali.h>
+#include <dali/devel-api/common/stage-devel.h>
+#include <dali/devel-api/update/frame-callback-interface.h>
+
+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<PhysicsWorld> ChipmunkPhysicsWorld::New(Dali::Actor rootActor, Dali::CallbackBase* updateCallback)
+{
+  std::unique_ptr<ChipmunkPhysicsWorld> world = std::make_unique<ChipmunkPhysicsWorld>(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 (file)
index 0000000..4f7b2d6
--- /dev/null
@@ -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 <dali-physics/internal/physics-world-impl.h>
+
+#include <chipmunk/chipmunk.h>
+#include <memory>
+
+namespace Dali::Toolkit::Physics::Internal
+{
+class ChipmunkPhysicsWorld : public PhysicsWorld
+{
+public:
+  static std::unique_ptr<PhysicsWorld> 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
index 9b2cf6e..87c7cb2 100644 (file)
@@ -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
 )
index 583bbfa..6aa2624 100644 (file)
@@ -35,7 +35,7 @@ class PhysicsAdaptor;
 
 using PhysicsActorPtr = Dali::IntrusivePtr<PhysicsActor>;
 
-class DALI_TOOLKIT_API PhysicsActor : public Dali::BaseObject
+class PhysicsActor : public Dali::BaseObject
 {
 public:
   PhysicsActor(Dali::Actor actor, Dali::Any body, PhysicsAdaptor& adaptor);
index dd20c0b..09b3408 100644 (file)
@@ -18,8 +18,6 @@
 #include <dali-physics/internal/physics-adaptor-impl.h>
 
 // External Headers
-#include <iostream>
-#include <map>
 #include <memory>
 #include <utility>
 
@@ -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<Physics::PhysicsAdaptor::ScopedPhysicsAccessor>(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<Vector3>(debugLayer, Actor::Property::POSITION, EqualToConstraint());
-  positionConstraint.AddSource(Source(mRootActor, Actor::Property::POSITION));
-  positionConstraint.Apply();
-  Constraint sizeConstraint = Constraint::New<Vector2>(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<Vector2>(mDebugActor, Actor::Property::SIZE, EqualToConstraint());
-  sizeConstraint2.AddSource(ParentSource(Actor::Property::SIZE));
-  sizeConstraint2.Apply();
-
-  debugLayer.Add(mDebugActor);
-
-  auto bulletWorld = mPhysicsWorld->GetNative().Get<btDiscreteDynamicsWorld*>();
-
-  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<uint32_t>(actor.GetProperty<int>(Actor::Property::ID));
-  btRigidBody* btBody = body.Get<btRigidBody*>();
-
-  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<btRigidBody*>();
-  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
index 9c1644a..02e651a 100644 (file)
@@ -24,7 +24,6 @@
 
 // INTERNAL INCLUDES
 #include <dali-physics/internal/physics-actor-impl.h>
-#include <dali-physics/internal/physics-debug-renderer.h>
 #include <dali-physics/internal/physics-world-impl.h>
 #include <dali-physics/public-api/physics-adaptor.h>
 
@@ -33,8 +32,13 @@ namespace Dali::Toolkit::Physics
 namespace Internal
 {
 class PhysicsAdaptor;
+class PhysicsDebugRenderer;
+
 using PhysicsAdaptorPtr = IntrusivePtr<PhysicsAdaptor>;
 
+// 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<PhysicsWorld>                 mPhysicsWorld;
   std::unordered_map<uint32_t, PhysicsActorPtr> mPhysicsActors;
   Dali::Actor                                   mRootActor;
-  Dali::Actor                                   mDebugActor;
 
   Dali::Matrix     mTransform;
   Dali::Matrix     mInverseTransform;
   Dali::Uint16Pair mSize;
 
-  std::unique_ptr<PhysicsDebugRenderer> mDebugRenderer;
-  Dali::SlotDelegate<PhysicsAdaptor>    mSlotDelegate;
+  Dali::SlotDelegate<PhysicsAdaptor> mSlotDelegate;
 };
 
 } //namespace Internal
index d8cd6af..cd43633 100644 (file)
 #include <dali-physics/internal/physics-world-impl.h>
 
 // External Headers
-#include <BulletCollision/NarrowPhaseCollision/btRaycastCallback.h>
-#include <btBulletCollisionCommon.h>
-#include <iostream>
-#include <map>
-#include <memory>
-#include <utility>
 
 // Internal Headers
 #include <dali/dali.h>
@@ -62,31 +56,16 @@ private: // Member variables
   PhysicsWorld& mPhysicsWorld;
 };
 
-using NativeWorld = btDiscreteDynamicsWorld*;
-
-std::unique_ptr<PhysicsWorld> PhysicsWorld::New(Dali::Actor rootActor, Dali::CallbackBase* updateCallback)
-{
-  std::unique_ptr<PhysicsWorld> world = std::make_unique<PhysicsWorld>(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;
index fa6108f..cb9d543 100644 (file)
@@ -24,7 +24,6 @@
 
 #include <dali-physics/public-api/physics-adaptor.h>
 
-#include <btBulletDynamicsCommon.h>
 #include <functional>
 #include <queue>
 
@@ -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<PhysicsWorld> 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<void(void)> 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<std::function<void(void)>> commandQueue;
   Dali::UpdateProxy::NotifySyncPoint    mNotifySyncPoint;
   Dali::CallbackBase*                   mUpdateCallback{nullptr};
   std::unique_ptr<FrameCallback>        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};
 };
index 0f454c7..6cb7384 100644 (file)
@@ -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
 )
index e4514bd..616c7b2 100644 (file)
@@ -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
index c5cf51f..5cc274b 100644 (file)
@@ -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();
 }
index e39945b..00b7e78 100644 (file)
@@ -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<btDiscreteDynamiscWorld*>();
      */
     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<PhysicsAdaptor::ScopedPhysicsAccessor>;
+
+  /**
+   * @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<PhysicsAdaptor::ScopedPhysicsAccessor>;
   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<void(void)> 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 (file)
index 0000000..1f4b6e8
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2023 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <dali-physics/public-api/physics-adaptor.h>
+
+#include <dali-physics/internal/physics-adaptor-impl.h>
+#include <dali-physics/internal/physics-world-impl.h>
+
+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
index 78611e8..431c5ce 100644 (file)
@@ -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