--- /dev/null
+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}
+)
#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);
}
--- /dev/null
+/*
+ * Copyright (c) 2023 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#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;
+}
--- /dev/null
+/*
+ * Copyright (c) 2023 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#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;
+}
-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
${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
)
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
)
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
)
--- /dev/null
+#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);
+}
const char* BALL_IMAGE = TEST_RESOURCE_DIR "/gallery-small-1.jpg";
-int UtcDaliPhysicsActorNew(void)
+int UtcDaliPhysics3DActorNew(void)
{
ToolkitTestApplication application;
END_TEST;
}
-int UtcDaliPhysicsActorDownCastP(void)
+int UtcDaliPhysics3DActorDownCastP(void)
{
ToolkitTestApplication application;
END_TEST;
}
-int UtcDaliPhysicsActorDownCastN(void)
+int UtcDaliPhysics3DActorDownCastN(void)
{
BaseHandle uninitializedHandle;
PhysicsActor actor = PhysicsActor::DownCast(uninitializedHandle);
END_TEST;
}
-int UtcDaliPhysicsActorMoveConstructor(void)
+int UtcDaliPhysics3DActorMoveConstructor(void)
{
ToolkitTestApplication application;
tet_infoline("Testing the move constructor");
END_TEST;
}
-int UtcDaliPhysicsActorCopyConstructor(void)
+int UtcDaliPhysics3DActorCopyConstructor(void)
{
ToolkitTestApplication application;
tet_infoline("Testing the move constructor");
END_TEST;
}
-int UtcDaliPhysicsActorCopyAssign(void)
+int UtcDaliPhysics3DActorCopyAssign(void)
{
ToolkitTestApplication application;
tet_infoline("Testing the copy assign");
END_TEST;
}
-int UtcDaliPhysicsActorMoveAssignment(void)
+int UtcDaliPhysics3DActorMoveAssignment(void)
{
ToolkitTestApplication application;
tet_infoline("Testing the move constructor");
END_TEST;
}
-int UtcDaliPhysicsActorGetIdP(void)
+int UtcDaliPhysics3DActorGetIdP(void)
{
ToolkitTestApplication application;
tet_infoline("Testing the ID Getter");
END_TEST;
}
-int UtcDaliPhysicsActorGetIdN(void)
+int UtcDaliPhysics3DActorGetIdN(void)
{
ToolkitTestApplication application;
tet_infoline("Testing the ID Getter");
END_TEST;
}
-int UtcDaliPhysicsActorGetBodyP(void)
+int UtcDaliPhysics3DActorGetBodyP(void)
{
ToolkitTestApplication application;
tet_infoline("Testing the body Getter");
END_TEST;
}
-int UtcDaliPhysicsActorGetBodyN(void)
+int UtcDaliPhysics3DActorGetBodyN(void)
{
ToolkitTestApplication application;
tet_infoline("Testing the ID Getter");
END_TEST;
}
-int UtcDaliPhysicsActorSetPosition(void)
+int UtcDaliPhysics3DActorSetPosition(void)
{
tet_infoline("Test the AsyncSetPhysicsPosition() function");
END_TEST;
}
-int UtcDaliPhysicsActorSetRotation1(void)
+int UtcDaliPhysics3DActorSetRotation1(void)
{
tet_infoline("Test the AsyncSetPhysicsRotation() function");
END_TEST;
}
-int UtcDaliPhysicsActorSetRotation2(void)
+int UtcDaliPhysics3DActorSetRotation2(void)
{
tet_infoline("Test the AsyncSetPhysicsRotation() function");
END_TEST;
}
-int UtcDaliPhysicsActorGetActorPosition(void)
+int UtcDaliPhysics3DActorGetActorPosition(void)
{
tet_infoline("Test the GetActorPosition() function");
END_TEST;
}
-int UtcDaliPhysicsActorGetActorRotation(void)
+int UtcDaliPhysics3DActorGetActorRotation(void)
{
tet_infoline("Test the GetActorRotation() function");
END_TEST;
}
-int UtcDaliPhysicsActorGetPhysicsPosition(void)
+int UtcDaliPhysics3DActorGetPhysicsPosition(void)
{
tet_infoline("Test the GetPhysicsPosition() function");
END_TEST;
}
-int UtcDaliPhysicsActorGetPhysicsRotation(void)
+int UtcDaliPhysics3DActorGetPhysicsRotation(void)
{
tet_infoline("Test the GetPhysicsRotation() function");
return body;
}
-int UtcDaliPhysicsCreateAdaptorP1(void)
+int UtcDaliPhysics3DCreateAdaptorP1(void)
{
ToolkitTestApplication application;
END_TEST;
}
-int UtcDaliPhysicsCreateAdaptorN1(void)
+int UtcDaliPhysics3DCreateAdaptorN1(void)
{
ToolkitTestApplication application;
END_TEST;
}
-int UtcDaliPhysicsDowncastP1(void)
+int UtcDaliPhysics3DDowncastP1(void)
{
ToolkitTestApplication application;
END_TEST;
}
-int UtcDaliPhysicsDowncastN1(void)
+int UtcDaliPhysics3DDowncastN1(void)
{
BaseHandle handle;
auto adaptor = PhysicsAdaptor::DownCast(handle);
END_TEST;
}
-int UtcDaliPhysicsAdaptorMoveConstructor(void)
+int UtcDaliPhysics3DAdaptorMoveConstructor(void)
{
ToolkitTestApplication application;
tet_infoline("Testing the move constructor");
END_TEST;
}
-int UtcDaliPhysicsAdaptorCopyConstructor(void)
+int UtcDaliPhysics3DAdaptorCopyConstructor(void)
{
ToolkitTestApplication application;
tet_infoline("Testing the move constructor");
END_TEST;
}
-int UtcDaliPhysicsAdaptorCopyAssign(void)
+int UtcDaliPhysics3DAdaptorCopyAssign(void)
{
ToolkitTestApplication application;
tet_infoline("Testing the copy assign");
END_TEST;
}
-int UtcDaliPhysicsAdaptorMoveAssignment(void)
+int UtcDaliPhysics3DAdaptorMoveAssignment(void)
{
ToolkitTestApplication application;
tet_infoline("Testing the move constructor");
END_TEST;
}
-int UtcDaliPhysicsSetTimestep(void)
+int UtcDaliPhysics3DSetTimestep(void)
{
ToolkitTestApplication application;
END_TEST;
}
-int UtcDaliPhysicsGetTimestep(void)
+int UtcDaliPhysics3DGetTimestep(void)
{
ToolkitTestApplication application;
END_TEST;
}
-int UtcDaliPhysicsGetPhysicsAccessorP1(void)
+int UtcDaliPhysics3DGetPhysicsAccessorP1(void)
{
ToolkitTestApplication application;
END_TEST;
}
-int UtcDaliPhysicsGetPhysicsAccessorN1(void)
+int UtcDaliPhysics3DGetPhysicsAccessorN1(void)
{
ToolkitTestApplication application;
END_TEST;
}
-int UtcDaliPhysicsAdaptorGetRootActor(void)
+int UtcDaliPhysics3DAdaptorGetRootActor(void)
{
tet_infoline("Test that the root actor can be retrieved");
END_TEST;
}
-int UtcDaliPhysicsAdaptorCreateDebugLayer(void)
+int UtcDaliPhysics3DAdaptorCreateDebugLayer(void)
{
ToolkitTestApplication application;
Matrix transform(true);
END_TEST;
}
-int UtcDaliPhysicsAdaptorTranslateToPhysicsSpace1(void)
+int UtcDaliPhysics3DAdaptorTranslateToPhysicsSpace1(void)
{
ToolkitTestApplication application;
Matrix transform(false);
END_TEST;
}
-int UtcDaliPhysicsAdaptorTranslateToPhysicsSpace2(void)
+int UtcDaliPhysics3DAdaptorTranslateToPhysicsSpace2(void)
{
ToolkitTestApplication application;
Matrix transform(false);
END_TEST;
}
-int UtcDaliPhysicsAdaptorTranslateToPhysicsSpace3(void)
+int UtcDaliPhysics3DAdaptorTranslateToPhysicsSpace3(void)
{
ToolkitTestApplication application;
Matrix transform(false);
END_TEST;
}
-int UtcDaliPhysicsAdaptorTranslateToPhysicsSpace4(void)
+int UtcDaliPhysics3DAdaptorTranslateToPhysicsSpace4(void)
{
ToolkitTestApplication application;
Matrix transform(false);
END_TEST;
}
-int UtcDaliPhysicsAdaptorTranslateToPhysicsSpace5(void)
+int UtcDaliPhysics3DAdaptorTranslateToPhysicsSpace5(void)
{
ToolkitTestApplication application;
Matrix transform(false);
END_TEST;
}
-int UtcDaliPhysicsAdaptorTranslateFromPhysicsSpace1(void)
+int UtcDaliPhysics3DAdaptorTranslateFromPhysicsSpace1(void)
{
ToolkitTestApplication application;
Matrix transform(false);
END_TEST;
}
-int UtcDaliPhysicsAdaptorConvertVectorToPhysicsSpace01(void)
+int UtcDaliPhysics3DAdaptorConvertVectorToPhysicsSpace01(void)
{
ToolkitTestApplication application;
Matrix transform(false);
END_TEST;
}
-int UtcDaliPhysicsAdaptorConvertVectorToPhysicsSpace02(void)
+int UtcDaliPhysics3DAdaptorConvertVectorToPhysicsSpace02(void)
{
ToolkitTestApplication application;
Matrix transform(false);
END_TEST;
}
-int UtcDaliPhysicsAdaptorConvertVectorFromPhysicsSpace01(void)
+int UtcDaliPhysics3DAdaptorConvertVectorFromPhysicsSpace01(void)
{
ToolkitTestApplication application;
Matrix transform(false);
END_TEST;
}
-int UtcDaliPhysicsAdaptorConvertVectorFromPhysicsSpace02(void)
+int UtcDaliPhysics3DAdaptorConvertVectorFromPhysicsSpace02(void)
{
ToolkitTestApplication application;
Matrix transform(false);
END_TEST;
}
-int UtcDaliPhysicsAdaptorSetTransformAndSize(void)
+int UtcDaliPhysics3DAdaptorSetTransformAndSize(void)
{
ToolkitTestApplication application;
Matrix transform(false);
END_TEST;
}
-int UtcDaliPhysicsAdaptorSetIntegrationState(void)
+int UtcDaliPhysics3DAdaptorSetIntegrationState(void)
{
tet_infoline("Test that changing the integration state is reflected");
END_TEST;
}
-int UtcDaliPhysicsAdaptorGetIntegrationState(void)
+int UtcDaliPhysics3DAdaptorGetIntegrationState(void)
{
tet_infoline("Test that changing the integration state is reflected");
END_TEST;
}
-int UtcDaliPhysicsAdaptorSetDebugState(void)
+int UtcDaliPhysics3DAdaptorSetDebugState(void)
{
tet_infoline("Test that changing the debug state is reflected");
END_TEST;
}
-int UtcDaliPhysicsAdaptorGetDebugState(void)
+int UtcDaliPhysics3DAdaptorGetDebugState(void)
{
tet_infoline("Test that changing the debug state is reflected");
END_TEST;
}
-int UtcDaliPhysicsAdaptorAddActorBody(void)
+int UtcDaliPhysics3DAdaptorAddActorBody(void)
{
tet_infoline("Test that an actor/body pair can be added");
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");
END_TEST;
}
-int UtcDaliPhysicsAdaptorBuildPickingRay(void)
+int UtcDaliPhysics3DAdaptorBuildPickingRay(void)
{
tet_infoline("Test that a touch can be converted to a picking ray");
END_TEST;
}
-int UtcDaliPhysicsAdaptorProjectPoint(void)
+int UtcDaliPhysics3DAdaptorProjectPoint(void)
{
tet_infoline("Test that a point is projected into physics space");
END_TEST;
}
-int UtcDaliPhysicsAdaptorQueue(void)
+int UtcDaliPhysics3DAdaptorQueue(void)
{
tet_infoline("Test that Queue and CreateSyncPoint both work");
END_TEST;
}
-int UtcDaliPhysicsAdaptorCreateSyncPoint(void)
+int UtcDaliPhysics3DAdaptorCreateSyncPoint(void)
{
tet_infoline("Test that a delayed CreateSyncPoint delays update");
END_TEST;
}
-int UtcDaliPhysicsAdaptorHitTestP(void)
+int UtcDaliPhysics3DAdaptorHitTestP(void)
{
tet_infoline("Test that hit testing finds a body");
#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.
}
/**
- * 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
*/
}
/**
+ * 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
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)
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}
"${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
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}
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}
# 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
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"
)
Description: Dali Physics 2D library
Version: ${apiversion}
Requires: chipmunk2d
-Libs: -L${libdir}
+Libs: -L${libdir} -ldali2-physics-2d
Cflags: -I${includedir}
// 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
void PhysicsActor::Initialize(void)
{
- // RegisterObject?
}
void PhysicsActor::AsyncSetPhysicsPosition(Dali::Vector3 actorPosition)
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
--- /dev/null
+/*
+ * Copyright (c) 2023 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// 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
--- /dev/null
+#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;
* limitations under the License.
*/
+// External includes
#include <GLES3/gl3.h>
#include <LinearMath/btIDebugDraw.h>
#include <dali/dali.h>
--- /dev/null
+/*
+ * Copyright (c) 2023 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// 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
--- /dev/null
+#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
--- /dev/null
+/*
+ * Copyright (c) 2023 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// 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
--- /dev/null
+/*
+ * Copyright (c) 2023 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// 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
--- /dev/null
+#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
--- /dev/null
+/*
+ * Copyright (c) 2023 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// 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
--- /dev/null
+#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
-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
)
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);
#include <dali-physics/internal/physics-adaptor-impl.h>
// External Headers
-#include <iostream>
-#include <map>
#include <memory>
#include <utility>
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)
{
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)
mPhysicsWorld->SetTimestep(timestep);
}
-float PhysicsAdaptor::GetTimestep()
+float PhysicsAdaptor::GetTimestep() const
{
return mPhysicsWorld->GetTimestep();
}
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();
}
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)
mPhysicsWorld->CreateSyncPoint();
}
-} // namespace Internal
-} // namespace Dali::Toolkit::Physics
+} // namespace Dali::Toolkit::Physics::Internal
// 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>
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:
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
/**
* @copydoc Dali::Toolkit::Physics::PhysicsAdaptor::GetTimestep
*/
- float GetTimestep();
+ float GetTimestep() const;
/**
* @copydoc Dali::Toolkit::Physics::PhysicsAdaptor::GetPhysicsAccessor
/**
* @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
/**
* @copydoc Dali::Toolkit::Physics::PhysicsAdaptor::GetIntegrationState
*/
- Physics::PhysicsAdaptor::IntegrationState GetIntegrationState();
+ Physics::PhysicsAdaptor::IntegrationState GetIntegrationState() const;
/**
* @copydoc Dali::Toolkit::Physics::PhysicsAdaptor::SetDebugState
/**
* @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
*/
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
#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>
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
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()
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;
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;
#include <dali-physics/public-api/physics-adaptor.h>
-#include <btBulletDynamicsCommon.h>
#include <functional>
#include <queue>
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.
* 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);
/**
* @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
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};
};
-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
)
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
* 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
*/
/**
* @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,
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;
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
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());
}
GetImplementation(*this).SetTimestep(timestep);
}
-float PhysicsAdaptor::GetTimestep()
+float PhysicsAdaptor::GetTimestep() const
{
return GetImplementation(*this).GetTimestep();
}
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);
}
GetImplementation(*this).SetIntegrationState(state);
}
-Physics::PhysicsAdaptor::IntegrationState PhysicsAdaptor::GetIntegrationState()
+Physics::PhysicsAdaptor::IntegrationState PhysicsAdaptor::GetIntegrationState() const
{
return GetImplementation(*this).GetIntegrationState();
}
GetImplementation(*this).SetDebugState(state);
}
-Physics::PhysicsAdaptor::DebugState PhysicsAdaptor::GetDebugState()
+Physics::PhysicsAdaptor::DebugState PhysicsAdaptor::GetDebugState() const
{
return GetImplementation(*this).GetDebugState();
}
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();
}
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,
};
/**
- * 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.
{
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
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
*/
* 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
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.
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)
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
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
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
--- /dev/null
+/*
+ * Copyright (c) 2023 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#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
%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}
%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