/build/tizen/doc
/build/tizen/.cov
/build/tizen/CPack*.cmake
-/build/tizen/dali-physics/*
+
+/build/tizen/.ninja_deps
+/build/tizen/.ninja_log
+/build/tizen/build.ninja
+/build/tizen/rules.ninja
+
+/build/tizen/dali-physics/*.cmake
+/build/tizen/dali-physics/Makefile
+/build/tizen/dali-physics/CMakeCache.txt
+/build/tizen/dali-physics/CMakeFiles/
+/build/tizen/dali-physics/cmake_install.cmake
+/build/tizen/dali-physics/bullet3/
+/build/tizen/dali-physics/chipmunk2d/
+
/build/desktop
/packaging/home*
compile_commands.json
#!/usr/bin/perl
#
-# Copyright (c) 2020 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.
$files{$file}->{"patch"} = [@checklines];
$files{$file}->{"b_lines"} = {%b_lines};
- my %filter = map { $_ => $files{$_} } grep {m!^dali(-toolkit|-scene3d)?/!} (keys(%files));
+ my %filter = map { $_ => $files{$_} } grep {m!^dali(-toolkit|-scene3d|-physics)?/!} (keys(%files));
if($pd_debug)
{
--- /dev/null
+SET(PKG_NAME "dali-physics")
+
+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
+ 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(${CAPI_LIB} REQUIRED
+ dali2-core
+ dali2-adaptor
+ dali2-toolkit
+ dali2-physics-3d
+ bullet3
+)
+
+ADD_COMPILE_OPTIONS( -O0 -ggdb --coverage -Wall -Werror -DDEBUG_ENABLED)
+ADD_COMPILE_OPTIONS( ${${CAPI_LIB}_CFLAGS_OTHER} )
+
+ADD_DEFINITIONS(-DTEST_RESOURCE_DIR=\"${CMAKE_CURRENT_SOURCE_DIR}/../../resources\" )
+
+FOREACH(directory ${${CAPI_LIB}_LIBRARY_DIRS})
+ SET(CMAKE_CXX_LINK_FLAGS "${CMAKE_CXX_LINK_FLAGS} -L${directory}")
+ENDFOREACH(directory ${CAPI_LIB_LIBRARY_DIRS})
+
+INCLUDE_DIRECTORIES(
+ ../../../
+ ${${CAPI_LIB}_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}
+ ${${CAPI_LIB}_LIBRARIES}
+ -lpthread -ldl --coverage
+)
+
+INSTALL(PROGRAMS ${EXEC_NAME}
+ DESTINATION ${BIN_DIR}/${EXEC_NAME}
+)
--- /dev/null
+#include <test-harness.h>
+#include "tct-dali-physics-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 <bullet/btBulletDynamicsCommon.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 btRigidBody* CreateBody(btDiscreteDynamicsWorld* bulletWorld);
+
+const char* BALL_IMAGE = TEST_RESOURCE_DIR "/gallery-small-1.jpg";
+
+int UtcDaliPhysicsActorNew(void)
+{
+ ToolkitTestApplication application;
+
+ btRigidBody* body{nullptr};
+
+ Matrix transform(true);
+ Uint16Pair size(640, 480);
+ PhysicsAdaptor adaptor = PhysicsAdaptor::New(transform, size);
+
+ auto accessor = adaptor.GetPhysicsAccessor();
+ auto bulletWorld = accessor->GetNative().Get<btDiscreteDynamicsWorld*>();
+ body = CreateBody(bulletWorld);
+ Dali::Actor ballActor = Toolkit::ImageView::New(BALL_IMAGE);
+
+ PhysicsActor physicsActor = PhysicsActor::New(ballActor, body, adaptor);
+
+ DALI_TEST_CHECK(physicsActor);
+ END_TEST;
+}
+
+int UtcDaliPhysicsActorDownCastP(void)
+{
+ ToolkitTestApplication application;
+
+ Matrix transform(true);
+ Uint16Pair size(640, 480);
+ PhysicsAdaptor adaptor = PhysicsAdaptor::New(transform, size);
+
+ btRigidBody* body{nullptr};
+ auto accessor = adaptor.GetPhysicsAccessor();
+ auto bulletWorld = accessor->GetNative().Get<btDiscreteDynamicsWorld*>();
+ body = CreateBody(bulletWorld);
+ 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 UtcDaliPhysicsActorDownCastN(void)
+{
+ BaseHandle uninitializedHandle;
+ PhysicsActor actor = PhysicsActor::DownCast(uninitializedHandle);
+ DALI_TEST_CHECK(!actor);
+ END_TEST;
+}
+
+int UtcDaliPhysicsActorMoveConstructor(void)
+{
+ ToolkitTestApplication application;
+ tet_infoline("Testing the move constructor");
+
+ Matrix transform(true);
+ Uint16Pair size(640, 480);
+ PhysicsAdaptor adaptor = PhysicsAdaptor::New(transform, size);
+
+ btRigidBody* body{nullptr};
+ auto accessor = adaptor.GetPhysicsAccessor();
+ auto bulletWorld = accessor->GetNative().Get<btDiscreteDynamicsWorld*>();
+ body = CreateBody(bulletWorld);
+ 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 UtcDaliPhysicsActorCopyConstructor(void)
+{
+ ToolkitTestApplication application;
+ tet_infoline("Testing the move constructor");
+
+ Matrix transform(true);
+ Uint16Pair size(640, 480);
+ PhysicsAdaptor adaptor = PhysicsAdaptor::New(transform, size);
+
+ btRigidBody* body{nullptr};
+ auto accessor = adaptor.GetPhysicsAccessor();
+ auto bulletWorld = accessor->GetNative().Get<btDiscreteDynamicsWorld*>();
+ body = CreateBody(bulletWorld);
+ 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 UtcDaliPhysicsActorCopyAssign(void)
+{
+ ToolkitTestApplication application;
+ tet_infoline("Testing the copy assign");
+
+ Matrix transform(true);
+ Uint16Pair size(640, 480);
+ PhysicsAdaptor adaptor = PhysicsAdaptor::New(transform, size);
+
+ btRigidBody* body{nullptr};
+ auto accessor = adaptor.GetPhysicsAccessor();
+ auto bulletWorld = accessor->GetNative().Get<btDiscreteDynamicsWorld*>();
+ body = CreateBody(bulletWorld);
+ 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 UtcDaliPhysicsActorMoveAssignment(void)
+{
+ ToolkitTestApplication application;
+ tet_infoline("Testing the move constructor");
+
+ Matrix transform(true);
+ Uint16Pair size(640, 480);
+ PhysicsAdaptor adaptor = PhysicsAdaptor::New(transform, size);
+
+ btRigidBody* body{nullptr};
+ auto accessor = adaptor.GetPhysicsAccessor();
+ auto bulletWorld = accessor->GetNative().Get<btDiscreteDynamicsWorld*>();
+ body = CreateBody(bulletWorld);
+ 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 UtcDaliPhysicsActorGetIdP(void)
+{
+ ToolkitTestApplication application;
+ tet_infoline("Testing the ID Getter");
+
+ Matrix transform(true);
+ Uint16Pair size(640, 480);
+ PhysicsAdaptor adaptor = PhysicsAdaptor::New(transform, size);
+
+ btRigidBody* body{nullptr};
+ auto accessor = adaptor.GetPhysicsAccessor();
+ auto bulletWorld = accessor->GetNative().Get<btDiscreteDynamicsWorld*>();
+ body = CreateBody(bulletWorld);
+ 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 UtcDaliPhysicsActorGetIdN(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 UtcDaliPhysicsActorGetBodyP(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;
+ btRigidBody* body{nullptr};
+ {
+ auto accessor = adaptor.GetPhysicsAccessor();
+ auto bulletWorld = accessor->GetNative().Get<btDiscreteDynamicsWorld*>();
+ body = CreateBody(bulletWorld);
+ 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<btRigidBody*>(), body, TEST_LOCATION);
+
+ END_TEST;
+}
+
+int UtcDaliPhysicsActorGetBodyN(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 UtcDaliPhysicsActorSetPosition(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);
+
+ btRigidBody* body{nullptr};
+ PhysicsActor physicsActor;
+ {
+ auto accessor = adaptor.GetPhysicsAccessor();
+ auto bulletWorld = accessor->GetNative().Get<btDiscreteDynamicsWorld*>();
+ body = CreateBody(bulletWorld);
+ 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, -30), 0.0001f, TEST_LOCATION);
+ }
+
+ END_TEST;
+}
+
+int UtcDaliPhysicsActorSetRotation1(void)
+{
+ tet_infoline("Test the AsyncSetPhysicsRotation() 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);
+
+ btRigidBody* body{nullptr};
+ PhysicsActor physicsActor;
+ {
+ auto accessor = adaptor.GetPhysicsAccessor();
+ auto bulletWorld = accessor->GetNative().Get<btDiscreteDynamicsWorld*>();
+ body = CreateBody(bulletWorld);
+ physicsActor = adaptor.AddActorBody(ballActor, body);
+ physicsActor.AsyncSetPhysicsRotation(Quaternion(Degree(30), Vector3::YAXIS));
+ }
+
+ 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::YAXIS);
+ DALI_TEST_EQUALS(q, expected, 0.0001f, TEST_LOCATION);
+ }
+
+ END_TEST;
+}
+
+int UtcDaliPhysicsActorSetRotation2(void)
+{
+ tet_infoline("Test the AsyncSetPhysicsRotation() 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);
+
+ btRigidBody* body{nullptr};
+ PhysicsActor physicsActor;
+ {
+ auto accessor = adaptor.GetPhysicsAccessor();
+ auto bulletWorld = accessor->GetNative().Get<btDiscreteDynamicsWorld*>();
+ body = CreateBody(bulletWorld);
+ 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 UtcDaliPhysicsActorGetActorPosition(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);
+
+ btRigidBody* body{nullptr};
+ PhysicsActor physicsActor;
+ {
+ auto accessor = adaptor.GetPhysicsAccessor();
+ auto bulletWorld = accessor->GetNative().Get<btDiscreteDynamicsWorld*>();
+ body = CreateBody(bulletWorld);
+ 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();
+ DALI_TEST_EQUALS(physicsActor.GetActorPosition(), Vector3(10, 20, -30), 0.0001f, TEST_LOCATION);
+ }
+
+ END_TEST;
+}
+
+int UtcDaliPhysicsActorGetActorRotation(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);
+
+ btRigidBody* body{nullptr};
+ PhysicsActor physicsActor;
+ {
+ auto accessor = adaptor.GetPhysicsAccessor();
+ auto bulletWorld = accessor->GetNative().Get<btDiscreteDynamicsWorld*>();
+ body = CreateBody(bulletWorld);
+ 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 UtcDaliPhysicsActorGetPhysicsPosition(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);
+
+ btRigidBody* body{nullptr};
+ PhysicsActor physicsActor;
+ {
+ auto accessor = adaptor.GetPhysicsAccessor();
+ auto bulletWorld = accessor->GetNative().Get<btDiscreteDynamicsWorld*>();
+ body = CreateBody(bulletWorld);
+ 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, -30, 1);
+ DALI_TEST_EQUALS(physicsActor.GetPhysicsPosition(), Vector3(pos), 0.0001f, TEST_LOCATION);
+ }
+
+ END_TEST;
+}
+
+int UtcDaliPhysicsActorGetPhysicsRotation(void)
+{
+ tet_infoline("Test the GetPhysicsRotation() 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);
+
+ btRigidBody* body{nullptr};
+ PhysicsActor physicsActor;
+ {
+ auto accessor = adaptor.GetPhysicsAccessor();
+ auto bulletWorld = accessor->GetNative().Get<btDiscreteDynamicsWorld*>();
+ body = CreateBody(bulletWorld);
+ 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.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 <bullet/btBulletDynamicsCommon.h>
+
+using namespace Dali;
+using namespace Dali::Toolkit::Physics;
+
+void utc_dali_physics3d_startup(void)
+{
+ test_return_value = TET_UNDEF;
+}
+
+void utc_dali_physics3d_cleanup(void)
+{
+ test_return_value = TET_PASS;
+}
+
+btRigidBody* CreateBody(btDiscreteDynamicsWorld* bulletWorld)
+{
+ btSphereShape* ball = new btSphereShape(30);
+ btVector3 localInertia(0.f, 0.f, 0.f);
+ ball->calculateLocalInertia(10, localInertia);
+ btTransform transform;
+ transform.setIdentity();
+ auto* motionState = new btDefaultMotionState(transform);
+
+ btRigidBody::btRigidBodyConstructionInfo ci(10, motionState, ball, localInertia);
+
+ btRigidBody* body = new btRigidBody(ci);
+ body->setFriction(0.5f);
+ body->setRestitution(0.5f);
+ bulletWorld->addRigidBody(body);
+ return body;
+}
+
+int UtcDaliPhysicsCreateAdaptorP1(void)
+{
+ ToolkitTestApplication application;
+
+ Matrix transform(true);
+ Uint16Pair size(640, 480);
+
+ PhysicsAdaptor handle = PhysicsAdaptor::New(transform, size);
+ DALI_TEST_CHECK(handle);
+
+ END_TEST;
+}
+
+int UtcDaliPhysicsCreateAdaptorN1(void)
+{
+ ToolkitTestApplication application;
+
+ PhysicsAdaptor handle;
+ DALI_TEST_CHECK(!handle);
+
+ END_TEST;
+}
+
+int UtcDaliPhysicsDowncastP1(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 UtcDaliPhysicsDowncastN1(void)
+{
+ BaseHandle handle;
+ auto adaptor = PhysicsAdaptor::DownCast(handle);
+ DALI_TEST_CHECK(!adaptor);
+
+ DALI_TEST_CHECK(typeid(PhysicsAdaptor) == typeid(decltype(adaptor)));
+ END_TEST;
+}
+
+int UtcDaliPhysicsAdaptorMoveConstructor(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 UtcDaliPhysicsAdaptorCopyConstructor(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 UtcDaliPhysicsAdaptorCopyAssign(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 UtcDaliPhysicsAdaptorMoveAssignment(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 UtcDaliPhysicsSetTimestep(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 UtcDaliPhysicsGetTimestep(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 UtcDaliPhysicsGetPhysicsAccessorP1(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 UtcDaliPhysicsGetPhysicsAccessorN1(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 UtcDaliPhysicsAdaptorGetRootActor(void)
+{
+ tet_infoline("Test that the root actor can be retrieved");
+
+ 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);
+
+ 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 UtcDaliPhysicsAdaptorCreateDebugLayer(void)
+{
+ ToolkitTestApplication application;
+ Matrix transform(true);
+ 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);
+ Window window = DevelWindow::Get(rootActor);
+
+ Layer layer = adaptor.CreateDebugLayer(window);
+ DALI_TEST_CHECK(layer);
+
+ adaptor.SetDebugState(PhysicsAdaptor::DebugState::ON);
+
+ btRigidBody* body{nullptr};
+ {
+ auto accessor = adaptor.GetPhysicsAccessor();
+ auto bulletWorld = accessor->GetNative().Get<btDiscreteDynamicsWorld*>();
+ body = CreateBody(bulletWorld);
+ Dali::Actor ballActor = Toolkit::ImageView::New(TEST_RESOURCE_DIR "/gallery-small-1.jpg");
+ auto physicsActor = adaptor.AddActorBody(ballActor, body);
+ physicsActor.AsyncSetPhysicsPosition(Vector3(0.f, 0.f, 0.f));
+ }
+ Test::WaitForEventThreadTrigger(1);
+ application.SendNotification();
+ application.Render();
+
+ application.SendNotification();
+ application.Render();
+
+ END_TEST;
+}
+
+int UtcDaliPhysicsAdaptorTranslateToPhysicsSpace1(void)
+{
+ ToolkitTestApplication application;
+ Matrix transform(false);
+ transform.SetIdentityAndScale(Vector3(2.0f, 2.0f, 2.0f));
+ Uint16Pair size(640, 480);
+ PhysicsAdaptor adaptor = PhysicsAdaptor::New(transform, size);
+
+ Vector3 a(30, 20, 10);
+ Vector3 expected = a * 2.0f;
+ DALI_TEST_EQUALS(adaptor.TranslateToPhysicsSpace(a), expected, 0.0001f, TEST_LOCATION);
+
+ END_TEST;
+}
+
+int UtcDaliPhysicsAdaptorTranslateToPhysicsSpace2(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, 2.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 UtcDaliPhysicsAdaptorTranslateToPhysicsSpace3(void)
+{
+ ToolkitTestApplication application;
+ Matrix transform(false);
+ tet_infoline("Test that using an inverted Y scale also inverts quaternions");
+
+ 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); // We have mirrored along Y axis, so Z rot is opposite.
+
+ DALI_TEST_EQUALS(adaptor.TranslateToPhysicsSpace(q), qp, 0.0001f, TEST_LOCATION);
+
+ END_TEST;
+}
+
+int UtcDaliPhysicsAdaptorTranslateToPhysicsSpace4(void)
+{
+ ToolkitTestApplication application;
+ Matrix transform(false);
+ tet_infoline("Test that using an inverted Y scale also inverts quaternions");
+
+ 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); // We have mirrored along Y axis, so Z rot is opposite.
+
+ DALI_TEST_EQUALS(adaptor.TranslateToPhysicsSpace(q), qp, 0.0001f, TEST_LOCATION);
+
+ END_TEST;
+}
+
+int UtcDaliPhysicsAdaptorTranslateToPhysicsSpace5(void)
+{
+ ToolkitTestApplication application;
+ Matrix transform(false);
+ tet_infoline("Test that using an inverted Y scale also inverts quaternions, except along Y axis");
+
+ 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 UtcDaliPhysicsAdaptorTranslateFromPhysicsSpace1(void)
+{
+ ToolkitTestApplication application;
+ Matrix transform(false);
+ tet_infoline("Test that using a double scale halves position");
+
+ transform.SetIdentityAndScale(Vector3(2.0f, -2.0f, 2.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 UtcDaliPhysicsAdaptorConvertVectorToPhysicsSpace01(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 UtcDaliPhysicsAdaptorConvertVectorToPhysicsSpace02(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 UtcDaliPhysicsAdaptorConvertVectorFromPhysicsSpace01(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 UtcDaliPhysicsAdaptorConvertVectorFromPhysicsSpace02(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 UtcDaliPhysicsAdaptorSetTransformAndSize(void)
+{
+ ToolkitTestApplication application;
+ Matrix transform(false);
+ transform.SetIdentityAndScale(Vector3(2.0f, 2.0f, 2.0f));
+ Uint16Pair size(640, 480);
+ PhysicsAdaptor adaptor = PhysicsAdaptor::New(transform, size);
+
+ Vector3 a(30, 20, 10);
+ Vector3 expected = a * 2.0f;
+ 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 UtcDaliPhysicsAdaptorSetIntegrationState(void)
+{
+ tet_infoline("Test that changing the integration state is reflected");
+
+ 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);
+
+ DALI_TEST_CHECK(adaptor.GetIntegrationState() == PhysicsAdaptor::IntegrationState::ON);
+
+ adaptor.SetIntegrationState(PhysicsAdaptor::IntegrationState::OFF);
+ DALI_TEST_CHECK(adaptor.GetIntegrationState() == PhysicsAdaptor::IntegrationState::OFF);
+
+ END_TEST;
+}
+
+int UtcDaliPhysicsAdaptorGetIntegrationState(void)
+{
+ tet_infoline("Test that changing the integration state is reflected");
+
+ 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);
+
+ 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 UtcDaliPhysicsAdaptorSetDebugState(void)
+{
+ tet_infoline("Test that changing the debug state is reflected");
+
+ 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);
+
+ 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 UtcDaliPhysicsAdaptorGetDebugState(void)
+{
+ tet_infoline("Test that changing the debug state is reflected");
+
+ 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);
+
+ 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 UtcDaliPhysicsAdaptorAddActorBody(void)
+{
+ tet_infoline("Test that an actor/body pair can be added");
+
+ 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);
+
+ auto accessor = adaptor.GetPhysicsAccessor();
+ auto bulletWorld = accessor->GetNative().Get<btDiscreteDynamicsWorld*>();
+
+ btRigidBody* body = CreateBody(bulletWorld);
+ 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<btRigidBody*>(), body, TEST_LOCATION);
+
+ END_TEST;
+}
+
+int UtcDaliPhysicsAdaptorGetPhysicsActor(void)
+{
+ tet_infoline("Test that an actor/body pair can be retrieved");
+
+ 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);
+
+ auto accessor = adaptor.GetPhysicsAccessor();
+ auto bulletWorld = accessor->GetNative().Get<btDiscreteDynamicsWorld*>();
+
+ btRigidBody* body = CreateBody(bulletWorld);
+ 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 UtcDaliPhysicsAdaptorBuildPickingRay(void)
+{
+ tet_infoline("Test that a touch can be converted to a picking ray");
+
+ ToolkitTestApplication application;
+ Matrix transform(false);
+ transform.SetIdentityAndScale(Vector3(2.0f, 2.0f, 2.0f));
+ Uint16Pair size(640, 480);
+ PhysicsAdaptor adaptor = PhysicsAdaptor::New(transform, size);
+
+ Vector3 from, to;
+ adaptor.BuildPickingRay(Vector3(), -Vector3::ZAXIS, from, to);
+
+ DALI_TEST_EQUALS(from, Vector3(), 0.001f, TEST_LOCATION);
+ DALI_TEST_EQUALS(to, Vector3(0.0f, 0.0f, -20000.0f), 0.001f, TEST_LOCATION);
+
+ END_TEST;
+}
+
+int UtcDaliPhysicsAdaptorProjectPoint(void)
+{
+ tet_infoline("Test that a point is projected into physics space");
+
+ ToolkitTestApplication application;
+ Matrix transform(false);
+ transform.SetIdentityAndScale(Vector3(2.0f, 2.0f, 2.0f));
+ Uint16Pair size(640, 480);
+ PhysicsAdaptor adaptor = PhysicsAdaptor::New(transform, size);
+
+ // distance is in physics units, not DALi units!
+ Vector3 projectedPoint = adaptor.ProjectPoint(Vector3(), -Vector3::ZAXIS, 200);
+
+ DALI_TEST_EQUALS(projectedPoint, Vector3(0.0f, 0.0f, -200.0f), 0.001f, TEST_LOCATION);
+
+ END_TEST;
+}
+
+int UtcDaliPhysicsAdaptorQueue(void)
+{
+ tet_infoline("Test that Queue and CreateSyncPoint both work");
+
+ 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);
+
+ btRigidBody* body{nullptr};
+ {
+ 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);
+ }
+
+ tet_infoline("Test that Queue works without accessor");
+ adaptor.Queue([body]() {
+ body->getWorldTransform().setOrigin(btVector3(100.0f, 20.0f, 20.0f));
+ });
+ adaptor.CreateSyncPoint();
+
+ application.SendNotification();
+ application.Render();
+ // Should trigger an Update
+
+ {
+ auto accessor = adaptor.GetPhysicsAccessor();
+
+ btVector3 origin = body->getWorldTransform().getOrigin();
+ DALI_TEST_EQUALS(origin.x(), 100.0f, 0.001f, TEST_LOCATION);
+ DALI_TEST_EQUALS(origin.y(), 20.0f, 0.001f, TEST_LOCATION);
+ DALI_TEST_EQUALS(origin.z(), 20.0f, 0.001f, TEST_LOCATION);
+ }
+
+ END_TEST;
+}
+
+int UtcDaliPhysicsAdaptorCreateSyncPoint(void)
+{
+ tet_infoline("Test that a delayed CreateSyncPoint delays update");
+
+ 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);
+
+ btRigidBody* body{nullptr};
+ {
+ 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);
+
+ tet_infoline("Test that Queue works with accessor");
+ adaptor.Queue([body]() {
+ body->getWorldTransform().setOrigin(btVector3(100.0f, 20.0f, 20.0f));
+ });
+ }
+
+ // Should trigger an Update without processing queue
+ application.SendNotification();
+ application.Render();
+
+ {
+ auto accessor = adaptor.GetPhysicsAccessor();
+
+ btVector3 origin = body->getWorldTransform().getOrigin();
+ DALI_TEST_EQUALS(origin.x(), 0.0f, 0.001f, TEST_LOCATION);
+ DALI_TEST_EQUALS(origin.y(), 0.0f, 0.001f, TEST_LOCATION);
+ DALI_TEST_EQUALS(origin.z(), 0.0f, 0.001f, TEST_LOCATION);
+ }
+
+ // Should now execute queue
+ adaptor.CreateSyncPoint();
+ application.SendNotification();
+ application.Render();
+
+ {
+ auto accessor = adaptor.GetPhysicsAccessor();
+
+ btVector3 origin = body->getWorldTransform().getOrigin();
+ DALI_TEST_EQUALS(origin.x(), 100.0f, 0.001f, TEST_LOCATION);
+ DALI_TEST_EQUALS(origin.y(), 20.0f, 0.001f, TEST_LOCATION);
+ DALI_TEST_EQUALS(origin.z(), 20.0f, 0.001f, TEST_LOCATION);
+ }
+
+ END_TEST;
+}
+
+int UtcDaliPhysicsAdaptorHitTestP(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 bulletWorld = accessor->GetNative().Get<btDiscreteDynamicsWorld*>();
+ Dali::Actor ballActor = Toolkit::ImageView::New(TEST_RESOURCE_DIR "/gallery-small-1.jpg");
+ btRigidBody* body = CreateBody(bulletWorld);
+ body->getWorldTransform().setOrigin(btVector3(0.f, 0.f, 0.f));
+
+ 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 origin, direction;
+ Dali::HitTestAlgorithm::BuildPickingRay(scene.GetRenderTaskList().GetTask(0), center, origin, direction);
+ Vector3 from, to;
+ adaptor.BuildPickingRay(origin, direction, from, to); // Hit test centre of screen
+
+ {
+ auto accessor = adaptor.GetPhysicsAccessor();
+ Vector3 localPivot;
+ float distanceFromCamera;
+ auto body = accessor->HitTest(from, to, localPivot, distanceFromCamera);
+
+ DALI_TEST_CHECK(!body.Empty());
+ }
+
+ END_TEST;
+}
+
+// todo:
+// Hit Test
+// PhysicsDebugRenderer.... Elide?!
# List of test case sources (Only these get parsed for test cases)
SET(TC_SOURCES
- toolkit-direct-rendering-egl.cpp
utc-Dali-Alignment.cpp
utc-Dali-AnimatedImageVisual.cpp
utc-Dali-AnimatedVectorImageVisual.cpp
dali-toolkit-test-utils/toolkit-application.cpp
dali-toolkit-test-utils/toolkit-canvas-renderer.cpp
dali-toolkit-test-utils/toolkit-clipboard.cpp
+ dali-toolkit-test-utils/toolkit-direct-rendering-egl.cpp
dali-toolkit-test-utils/toolkit-event-thread-callback.cpp
dali-toolkit-test-utils/toolkit-environment-variable.cpp
dali-toolkit-test-utils/toolkit-input-method-context.cpp
std::chrono::steady_clock::duration timeSpan = endTime - tc.second.startTime;
double seconds = double(timeSpan.count()) * std::chrono::steady_clock::period::num / std::chrono::steady_clock::period::den;
- if(seconds > MAXIMUM_CHILD_LIFETIME)
+ if(4.9999 < seconds && seconds < 5 && !tc.second.finished)
+ {
+ printf("Child process %s is delayed: WCHAN:%s\n", tc.second.name, GetWChan(tc.first).c_str());
+ }
+ else if(seconds > MAXIMUM_CHILD_LIFETIME)
{
// Kill the child process. A subsequent call to waitpid will process signal result below.
if(!tc.second.finished)
--- /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 <EGL/egl.h>
+#include <GLES3/gl3.h>
+extern "C"
+{
+ // Flag to be set when we want shader compilation fail
+ bool gDirectRenderingFailCreateShader = false;
+
+ // Flag to be set when we want program linking fail
+ bool gDirectRenderingFailCreateProgram = false;
+
+ /**
+ * To test the multithreaded variant we need override EGL api
+ *
+ * The Direct Rendering uses GL directly and it's needed to override certain funtions in order
+ * to force code execution.
+ */
+ EGLContext eglCreateContext(EGLDisplay dpy, EGLConfig config, EGLContext share_context, const EGLint* attrib_list)
+ {
+ return EGLContext(0x12345678);
+ }
+
+ EGLBoolean eglGetConfigs(EGLDisplay dpy, EGLConfig* configs, EGLint config_size, EGLint* num_config)
+ {
+ static EGLConfig config;
+ if(num_config)
+ {
+ *num_config = 1;
+ }
+ if(configs)
+ {
+ configs[0] = config;
+ }
+
+ return EGL_TRUE;
+ }
+
+ GLuint glCreateProgram(void)
+ {
+ static uint32_t programId = 1;
+ return programId++;
+ }
+
+ GLuint glCreateShader(GLenum type)
+ {
+ static uint32_t shaderId = 1;
+ return shaderId++;
+ }
+
+ void glCompileShader(GLuint shader)
+ {
+ }
+
+ void glLinkProgram(GLuint program)
+ {
+ }
+
+ void glGenTextures(GLsizei n, GLuint* textures)
+ {
+ static GLuint texId = 1u;
+ for(auto i = 0; i < n; ++i)
+ {
+ textures[i] = texId++;
+ }
+ }
+
+ void glGetShaderiv(GLuint shader, GLenum pname, GLint* params)
+ {
+ if(pname == GL_COMPILE_STATUS)
+ {
+ params[0] = gDirectRenderingFailCreateShader ? GL_FALSE : GL_TRUE;
+ }
+ else if(pname == GL_INFO_LOG_LENGTH)
+ {
+ params[0] = 4;
+ }
+ }
+
+ void glGetProgramiv(GLuint shader, GLenum pname, GLint* params)
+ {
+ if(pname == GL_LINK_STATUS)
+ {
+ params[0] = gDirectRenderingFailCreateProgram ? GL_FALSE : GL_TRUE;
+ }
+ else if(pname == GL_INFO_LOG_LENGTH)
+ {
+ params[0] = 4;
+ }
+ }
+
+ void glGetShaderInfoLog(GLuint shader, GLsizei bufSize, GLsizei* length, GLchar* infoLog)
+ {
+ infoLog[0] = '0';
+ infoLog[1] = '\n';
+ }
+
+ void glGetProgramInfoLog(GLuint shader, GLsizei bufSize, GLsizei* length, GLchar* infoLog)
+ {
+ infoLog[0] = '0';
+ infoLog[1] = '\n';
+ }
+
+ void glDeleteSync(GLsync sync)
+ {
+ }
+
+ GLenum glClientWaitSync(GLsync sync, GLbitfield flags, GLuint64 timeout)
+ {
+ return GL_CONDITION_SATISFIED;
+ }
+
+ GLsync glFenceSync(GLenum condition, GLbitfield flags)
+ {
+ static uint32_t syncId = 0;
+ return reinterpret_cast<GLsync>(++syncId);
+ }
+
+ GLenum glCheckFramebufferStatus(GLenum target)
+ {
+ return GL_FRAMEBUFFER_COMPLETE;
+ }
+}
\ No newline at end of file
ToolkitTestApplication::ToolkitTestApplication(size_t surfaceWidth, size_t surfaceHeight, float horizontalDpi, float verticalDpi)
: TestApplication(surfaceWidth, surfaceHeight, horizontalDpi, verticalDpi, false /* Do not Initialize Core */),
- mMainWindow(new Dali::Window),
+ mMainWindow(),
mAdaptor(&AdaptorImpl::New()) // Need to create Adaptor first as many singletons in dali-adaptor need it
{
// Create Core next
// Override Scene creation in TestApplication by creating a window.
// The window will create a Scene & surface and set up the scene's surface appropriately.
- *mMainWindow = Window::New(PositionSize(0, 0, surfaceWidth, surfaceHeight), "");
- mScene = AdaptorImpl::GetScene(*mMainWindow);
+ mMainWindow = Window::New(PositionSize(0, 0, surfaceWidth, surfaceHeight), "");
+ mScene = AdaptorImpl::GetScene(mMainWindow);
mScene.SetDpi(Vector2(horizontalDpi, verticalDpi));
// Create render target for the scene
Accessibility::Accessible::SetObjectRegistry(mCore->GetObjectRegistry());
// This will also emit the window created signals
- AdaptorImpl::GetImpl(*mAdaptor).Start(*mMainWindow);
+ AdaptorImpl::GetImpl(*mAdaptor).Start(mMainWindow);
AdaptorImpl::GetImpl(*mAdaptor).SetApplication(*this);
Dali::LifecycleController lifecycleController = Dali::LifecycleController::Get();
#define DALI_TOOLKIT_TEST_APPLICATION_H
/*
- * Copyright (c) 2019 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.
*/
void RunIdles();
-private:
+ Dali::Window GetWindow()
+ {
+ return mMainWindow;
+ }
- std::unique_ptr<Dali::Window> mMainWindow;
+private:
+ Dali::Window mMainWindow;
std::unique_ptr< Adaptor > mAdaptor;
};
+++ /dev/null
-/*
-* Copyright (c) 2022 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 <EGL/egl.h>
-#include <GLES3/gl3.h>
-extern "C"
-{
-
-// Flag to be set when we want shader compilation fail
-bool gDirectRenderingFailCreateShader = false;
-
-// Flag to be set when we want program linking fail
-bool gDirectRenderingFailCreateProgram = false;
-
-/**
- * To test the multithreaded variant we need override EGL api
- *
- * The Direct Rendering uses GL directly and it's needed to override certain funtions in order
- * to force code execution.
- */
-EGLContext eglCreateContext (EGLDisplay dpy, EGLConfig config, EGLContext share_context, const EGLint *attrib_list)
-{
- return EGLContext(0x12345678);
-}
-
-EGLBoolean eglGetConfigs (EGLDisplay dpy, EGLConfig *configs, EGLint config_size, EGLint *num_config)
-{
- static EGLConfig config;
- if(num_config)
- {
- *num_config = 1;
- }
- if(configs)
- {
- configs[0] = config;
- }
-
- return EGL_TRUE;
-}
-
-GLuint glCreateProgram (void)
-{
- static uint32_t programId = 1;
- return programId++;
-}
-
-GLuint glCreateShader(GLenum type)
-{
- static uint32_t shaderId = 1;
- return shaderId++;
-}
-
-void glCompileShader(GLuint shader)
-{
-}
-
-void glLinkProgram (GLuint program)
-{
-}
-
-void glGenTextures(GLsizei n, GLuint *textures)
-{
- static GLuint texId = 1u;
- for(auto i = 0; i < n; ++i)
- {
- textures[i] = texId++;
- }
-}
-
-void glGetShaderiv(GLuint shader, GLenum pname, GLint *params)
-{
- if(pname == GL_COMPILE_STATUS)
- {
- params[0] = gDirectRenderingFailCreateShader ? GL_FALSE : GL_TRUE;
- }
- else if(pname == GL_INFO_LOG_LENGTH)
- {
- params[0] = 4;
- }
-}
-
-void glGetProgramiv(GLuint shader, GLenum pname, GLint *params)
-{
- if(pname == GL_LINK_STATUS)
- {
- params[0] = gDirectRenderingFailCreateProgram ? GL_FALSE : GL_TRUE;
- }
- else if(pname == GL_INFO_LOG_LENGTH)
- {
- params[0] = 4;
- }
-}
-
-void glGetShaderInfoLog (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog)
-{
- infoLog[0] = '0';
- infoLog[1] = '\n';
-}
-
-void glGetProgramInfoLog (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog)
-{
- infoLog[0] = '0';
- infoLog[1] = '\n';
-}
-
-void glDeleteSync (GLsync sync)
-{
-}
-
-GLenum glClientWaitSync (GLsync sync, GLbitfield flags, GLuint64 timeout)
-{
- return GL_CONDITION_SATISFIED;
-}
-
-GLsync glFenceSync (GLenum condition, GLbitfield flags)
-{
- static uint32_t syncId = 0;
- return reinterpret_cast<GLsync>(++syncId);
-}
-
-GLenum glCheckFramebufferStatus (GLenum target)
-{
- return GL_FRAMEBUFFER_COMPLETE;
-}
-
-}
\ No newline at end of file
dali2-*-config.cmake
libdali2-scene3d.so*
dali-shader-generator
+build.ninja
+rules.ninja
+.ninja_deps
+.ninja_log
add_subdirectory("${physics_dir}/third-party/chipmunk2d" chipmunk2d)
add_subdirectory("${physics_dir}/third-party/bullet3" bullet3)
-if (ENABLE_PKG_CONFIGURE)
- install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${core_pkg_cfg_file_2d} ${CMAKE_CURRENT_BINARY_DIR}/${core_pkg_cfg_file_3d}
- DESTINATION ${LIB_DIR}/pkgconfig
+# TODO: Split into 2 separate targets
+set(physics3d_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}
+ "${prefix_include_dir}"
+ "${repo_root_dir}/dali-physics/third-party/bullet3/src"
+)
+
+MESSAGE( STATUS "SOURCES: " ${physics3d_src_files})
+
+ADD_LIBRARY("${name}-3d" SHARED ${physics3d_src_files} )
+TARGET_LINK_LIBRARIES("${name}-3d" ${DALICORE_LDFLAGS}
+ dali2-toolkit
+ bullet3
+ ${COVERAGE})
+
+IF (ENABLE_PKG_CONFIGURE)
+ INSTALL(FILES
+ ${CMAKE_CURRENT_BINARY_DIR}/${core_pkg_cfg_file_2d}
+ ${CMAKE_CURRENT_BINARY_DIR}/${core_pkg_cfg_file_3d}
+ DESTINATION ${LIB_DIR}/pkgconfig )
+ENDIF()
+
+
+IF( INSTALL_CMAKE_MODULES )
+ MESSAGE(STATUS "Installing cmake modules & libs")
+ SET_TARGET_PROPERTIES( ${name}-3d
+ PROPERTIES
+ VERSION ${DALI_PHYSICS_VERSION}
+ SOVERSION ${${name}_VERSION_MAJOR}
+ CLEAN_DIRECT_OUPUT 1
)
-endif()
-
-if( INSTALL_CMAKE_MODULES )
- file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/${name}-2d-config.cmake "
+ IF( ENABLE_DEBUG )
+ SET( BIN_DIR "${BIN_DIR}/debug" )
+ SET( LIB_DIR "${LIB_DIR}/debug" )
+ ENDIF()
+
+ # Install library
+ INSTALL( TARGETS ${name}-3d
+ EXPORT ${name}-3d-targets
+ LIBRARY DESTINATION ${LIB_DIR}
+ ARCHIVE DESTINATION ${LIB_DIR}
+ RUNTIME DESTINATION ${BIN_DIR}
+ )
+
+ # Install the cmake modules.
+ INSTALL(
+ EXPORT ${name}-3d-targets
+ NAMESPACE ${name}-3d::
+ FILE ${name}-3d-targets.cmake
+ DESTINATION share/${name}-3d
+ )
+
+ FILE(WRITE ${CMAKE_CURRENT_BINARY_DIR}/${name}-2d-config.cmake "
include(CMakeFindDependencyMacro)
include(\${CMAKE_CURRENT_LIST_DIR}/${name}-2d-targets.cmake)
")
- install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${name}-2d-config.cmake DESTINATION share/${name}-2d)
+ INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/${name}-2d-config.cmake DESTINATION share/${name}-2d)
- file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/${name}-3d-config.cmake "
+ FILE(WRITE ${CMAKE_CURRENT_BINARY_DIR}/${name}-3d-config.cmake "
include(CMakeFindDependencyMacro)
include(\${CMAKE_CURRENT_LIST_DIR}/${name}-3d-targets.cmake)
")
- install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${name}-3d-config.cmake DESTINATION share/${name}-3d)
-endif()
+ INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/${name}-3d-config.cmake DESTINATION share/${name}-3d)
+
+ELSE()
+ MESSAGE(STATUS "Installing libs")
+ INSTALL( TARGETS ${name}-3d DESTINATION ${LIB_DIR} )
+
+ENDIF()
+# Install headers
+install( FILES ${physics3d_public_api_header_files}
+ DESTINATION "${INCLUDE_DIR}/dali-physics/public-api"
+ )
+install( FILES ${physics_dir}/dali-physics.h
+ DESTINATION "${INCLUDE_DIR}/dali-physics"
+ )
Description: Dali Physics 3D library
Version: ${apiversion}
Requires: bullet3
-Libs: -L${libdir}
+Libs: -L${libdir} -ldali2-physics-3d
Cflags: -I${includedir}
--- /dev/null
+# Overview
+
+The physics library is a small frontend to Chipmunk or Bullet libraries. It
+provides a safe mechanism to initialize and access the physics world from the
+event thread, whilst running the integration step in the Update thread.
+
+A queueing mechanism is provided to execute native functions on the Update
+thread prior to running the integration step. (This enables DALi properties
+and physics properties (e.g. position or orientation) to be synced in the same frame)
+
+DALi actors that are mapped to physics bodies are automatically updated after
+the integration step.
+
--- /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/public-api/physics-actor.h>
+#include <dali-physics/public-api/physics-adaptor.h>
--- /dev/null
+set(physics3d_internal_dir "${physics_dir}/internal")
+
+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
+)
--- /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>
+
+namespace Dali::Toolkit::Physics::Internal
+{
+namespace
+{
+inline btVector3 fromVec3(Dali::Vector3 vec3)
+{
+ return btVector3(vec3.x, vec3.y, vec3.z);
+}
+inline Dali::Vector3 toVec3(btVector3 vec3)
+{
+ return Dali::Vector3(vec3.x(), vec3.y(), vec3.z());
+}
+
+inline btQuaternion fromQuat(Dali::Quaternion q)
+{
+ return btQuaternion(q.mVector.x, q.mVector.y, q.mVector.z, q.mVector.w);
+}
+inline Dali::Quaternion toQuat(btQuaternion q)
+{
+ return Dali::Quaternion(q.w(), q.x(), q.y(), q.z());
+}
+
+} //Anonymous namespace
+
+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)
+{
+ // RegisterObject?
+}
+
+void PhysicsActor::AsyncSetPhysicsPosition(Dali::Vector3 actorPosition)
+{
+ // Queue task
+ btRigidBody* body = mBody.Get<btRigidBody*>();
+ auto pos = fromVec3(mAdaptor.TranslateToPhysicsSpace(actorPosition));
+ mAdaptor.Queue([body, pos] { body->getWorldTransform().setOrigin(pos); });
+}
+
+void PhysicsActor::AsyncSetPhysicsRotation(Dali::Quaternion rotation)
+{
+ // Queue task
+ btRigidBody* body = mBody.Get<btRigidBody*>();
+ auto q = fromQuat(mAdaptor.TranslateToPhysicsSpace(rotation));
+ mAdaptor.Queue([body, q]() { body->getWorldTransform().setRotation(q); });
+}
+
+Dali::Vector3 PhysicsActor::GetPhysicsPosition() const
+{
+ btRigidBody* body = mBody.Get<btRigidBody*>();
+ return toVec3(body->getWorldTransform().getOrigin());
+}
+
+Dali::Quaternion PhysicsActor::GetPhysicsRotation() const
+{
+ btRigidBody* body = mBody.Get<btRigidBody*>();
+ return toQuat(body->getWorldTransform().getRotation());
+}
+
+Dali::Vector3 PhysicsActor::GetActorPosition() const
+{
+ btRigidBody* body = mBody.Get<btRigidBody*>();
+ const btTransform& transform = body->getWorldTransform();
+ const btVector3& position = transform.getOrigin();
+ return mAdaptor.TranslateFromPhysicsSpace(Vector3(position.getX(), position.getY(), position.getZ()));
+}
+
+Dali::Quaternion PhysicsActor::GetActorRotation() const
+{
+ btRigidBody* body = mBody.Get<btRigidBody*>();
+ 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
+#ifndef DALI_TOOLKIT_PHYSICS_INTERNAL_ACTOR_H
+#define DALI_TOOLKIT_PHYSICS_INTERNAL_ACTOR_H
+
+/*
+ * 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.
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/actors/actor.h>
+#include <dali/public-api/object/any.h>
+#include <dali/public-api/object/base-object.h>
+
+// INTERNAL INCLUDES
+#include <dali-physics/public-api/physics-actor.h>
+#include <dali-toolkit/public-api/dali-toolkit-common.h>
+
+namespace Dali::Toolkit::Physics
+{
+namespace Internal
+{
+class PhysicsActor;
+class PhysicsAdaptor;
+
+using PhysicsActorPtr = Dali::IntrusivePtr<PhysicsActor>;
+
+class DALI_TOOLKIT_API PhysicsActor : public Dali::BaseObject
+{
+public:
+ PhysicsActor(Dali::Actor actor, Dali::Any body, PhysicsAdaptor& adaptor);
+ ~PhysicsActor() override;
+ PhysicsActor(const PhysicsActor& handle) = delete;
+ PhysicsActor& operator=(const PhysicsActor& handle) = delete;
+
+ /**
+ * @copydoc Dali::Toolkit::Physics::PhysicsActor::New()
+ */
+ static PhysicsActorPtr New(Dali::Actor actor, Dali::Any body, PhysicsAdaptor& adaptor);
+
+ void Initialize(void);
+
+ /**
+ * @copydoc Dali::Toolkit::Physics::PhysicsActor::GetId
+ */
+ uint32_t GetId() const
+ {
+ return mActorId;
+ }
+
+ /**
+ * @copydoc Dali::Toolkit::Physics::PhysicsActor::GetBody
+ */
+ Dali::Any GetBody() const
+ {
+ return mBody;
+ }
+
+ /**
+ * @copydoc Dali::Toolkit::Physics::PhysicsActor::AsyncSetPhysicsPosition
+ */
+ void AsyncSetPhysicsPosition(Dali::Vector3 actorPosition);
+
+ /**
+ * @copydoc Dali::Toolkit::Physics::PhysicsActor::AsyncSetPhysicsRotation
+ */
+ void AsyncSetPhysicsRotation(Dali::Quaternion actorRotation);
+
+ /**
+ * @copydoc Dali::Toolkit::Physics::PhysicsActor::GetPhysicsPosition
+ */
+ Dali::Vector3 GetPhysicsPosition() const;
+
+ /**
+ * @copydoc Dali::Toolkit::Physics::PhysicsActor::GetPhysicsRotation
+ */
+ Dali::Quaternion GetPhysicsRotation() const;
+
+ /**
+ * @copydoc Dali::Toolkit::Physics::PhysicsActor::GetActorPosition
+ */
+ Dali::Vector3 GetActorPosition() const;
+
+ /**
+ * @copydoc Dali::Toolkit::Physics::PhysicsActor::GetActorRotation
+ */
+ Dali::Quaternion GetActorRotation() const;
+
+private:
+ PhysicsAdaptor& mAdaptor;
+ uint32_t mActorId{0};
+ Dali::Any mBody;
+};
+
+} // namespace Internal
+
+inline Internal::PhysicsActor& GetImplementation(Physics::PhysicsActor& physics)
+{
+ DALI_ASSERT_ALWAYS(physics && "Physics actor handle is empty");
+ BaseObject& handle = physics.GetBaseObject();
+ return static_cast<Internal::PhysicsActor&>(handle);
+}
+
+inline const Internal::PhysicsActor& GetImplementation(const Physics::PhysicsActor& physics)
+{
+ DALI_ASSERT_ALWAYS(physics && "Physics actor handle is empty");
+ const BaseObject& handle = physics.GetBaseObject();
+ return static_cast<const Internal::PhysicsActor&>(handle);
+}
+
+} // namespace Dali::Toolkit::Physics
+
+#endif //DALI_TOOLKIT_PHYSICS_INTERNAL_ACTOR_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/physics-adaptor-impl.h>
+
+// External Headers
+#include <iostream>
+#include <map>
+#include <memory>
+#include <utility>
+
+// Internal Headers
+#include <dali-physics/internal/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
+
+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)
+{
+ 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[Layer::Property::BEHAVIOR] = Layer::LAYER_3D;
+ mRootActor[Layer::Property::DEPTH_TEST] = true;
+ mRootActor[Actor::Property::SIZE] = Vector2(mSize.GetWidth(), mSize.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));
+}
+
+void PhysicsAdaptor::SetTimestep(float timestep)
+{
+ mPhysicsWorld->SetTimestep(timestep);
+}
+
+float PhysicsAdaptor::GetTimestep()
+{
+ return mPhysicsWorld->GetTimestep();
+}
+
+Physics::PhysicsAdaptor::ScopedPhysicsAccessorPtr PhysicsAdaptor::GetPhysicsAccessor()
+{
+ 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()
+{
+ return mPhysicsWorld->GetIntegrationState();
+}
+
+void PhysicsAdaptor::SetDebugState(Physics::PhysicsAdaptor::DebugState state)
+{
+ mPhysicsWorld->SetDebugState(state);
+}
+
+Physics::PhysicsAdaptor::DebugState PhysicsAdaptor::GetDebugState()
+{
+ 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()
+{
+ 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)
+ {
+ // Get position, orientation from physics world.
+ Vector3 position = actor.second->GetActorPosition();
+ updateProxy->BakePosition(actor.first, position);
+ Quaternion rotation = actor.second->GetActorRotation();
+ updateProxy->BakeOrientation(actor.first, rotation);
+ }
+}
+
+void PhysicsAdaptor::Queue(std::function<void()> function)
+{
+ mPhysicsWorld->Queue(function);
+}
+
+void PhysicsAdaptor::CreateSyncPoint()
+{
+ mPhysicsWorld->CreateSyncPoint();
+}
+
+} // namespace Internal
+} // namespace Dali::Toolkit::Physics
--- /dev/null
+#ifndef DALI_TOOLKIT_PHYSICS_INTERNAL_ADAPTOR_H
+#define DALI_TOOLKIT_PHYSICS_INTERNAL_ADAPTOR_H
+
+/*
+ * 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
+#include <dali/public-api/object/base-object.h>
+#include <memory>
+#include <unordered_map>
+
+// 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 Dali::Toolkit::Physics
+{
+namespace Internal
+{
+class PhysicsAdaptor;
+using PhysicsAdaptorPtr = IntrusivePtr<PhysicsAdaptor>;
+
+class PhysicsAdaptor : public BaseObject
+{
+public:
+ PhysicsAdaptor();
+
+ /**
+ * A reference counted object may only be deleted by calling Unreference()
+ */
+ ~PhysicsAdaptor() override;
+
+ // Remove copy constructor and copy assignment
+ 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);
+
+ /**
+ * @copydoc Dali::Toolkit::Physics::PhysicsAdaptor::SetTimestep
+ */
+ void SetTimestep(float timestep);
+
+ /**
+ * @copydoc Dali::Toolkit::Physics::PhysicsAdaptor::GetTimestep
+ */
+ float GetTimestep();
+
+ /**
+ * @copydoc Dali::Toolkit::Physics::PhysicsAdaptor::GetPhysicsAccessor
+ */
+ Physics::PhysicsAdaptor::ScopedPhysicsAccessorPtr GetPhysicsAccessor();
+
+ /**
+ * @copydoc Dali::Toolkit::Physics::PhysicsAdaptor::CreateDebugLayer
+ */
+ Dali::Layer CreateDebugLayer(Dali::Window window);
+
+ /**
+ * @copydoc Dali::Toolkit::Physics::PhysicsAdaptor::TranslateToPhysicsSpace
+ */
+ Dali::Vector3 TranslateToPhysicsSpace(Dali::Vector3 vector);
+
+ /**
+ * @copydoc Dali::Toolkit::Physics::PhysicsAdaptor::TranslateToPhysicsSpace
+ */
+ Dali::Quaternion TranslateToPhysicsSpace(Dali::Quaternion rotation);
+
+ /**
+ * @copydoc Dali::Toolkit::Physics::PhysicsAdaptor::TranslateFromPhysicsSpace
+ */
+ Dali::Vector3 TranslateFromPhysicsSpace(Dali::Vector3 vector);
+
+ /**
+ * @copydoc Dali::Toolkit::Physics::PhysicsAdaptor::TranslateFromPhysicsSpace
+ */
+ Dali::Quaternion TranslateFromPhysicsSpace(Quaternion rotation);
+
+ /**
+ * @copydoc Dali::Toolkit::Physics::PhysicsAdaptor::ConvertVectorToPhysicsSpace
+ */
+ Dali::Vector3 ConvertVectorToPhysicsSpace(Dali::Vector3 vector);
+
+ /**
+ * @copydoc Dali::Toolkit::Physics::PhysicsAdaptor::ConvertVectorFromPhysicsSpace
+ */
+ Dali::Vector3 ConvertVectorFromPhysicsSpace(Dali::Vector3 vector);
+
+ /**
+ * @copydoc Dali::Toolkit::Physics::PhysicsAdaptor::SetTransformAndSize
+ */
+ void SetTransformAndSize(const Dali::Matrix& transform, Uint16Pair size);
+
+ /**
+ * @copydoc Dali::Toolkit::Physics::PhysicsAdaptor::SetIntegrationState
+ */
+ void SetIntegrationState(Physics::PhysicsAdaptor::IntegrationState state);
+
+ /**
+ * @copydoc Dali::Toolkit::Physics::PhysicsAdaptor::GetIntegrationState
+ */
+ Physics::PhysicsAdaptor::IntegrationState GetIntegrationState();
+
+ /**
+ * @copydoc Dali::Toolkit::Physics::PhysicsAdaptor::SetDebugState
+ */
+ void SetDebugState(Physics::PhysicsAdaptor::DebugState state);
+
+ /**
+ * @copydoc Dali::Toolkit::Physics::PhysicsAdaptor::GetDebugState
+ */
+ Physics::PhysicsAdaptor::DebugState GetDebugState();
+
+ /**
+ * @copydoc Dali::Toolkit::Physics::PhysicsAdaptor::AddActorBody
+ */
+ PhysicsActorPtr AddActorBody(Dali::Actor actor, Dali::Any body);
+
+ /**
+ * @copydoc Dali::Toolkit::Physics::PhysicsAdaptor::GetPhysicsActor
+ */
+ PhysicsActorPtr GetPhysicsActor(Dali::Any body);
+
+ /**
+ * @copydoc Dali::Toolkit::Physics::PhysicsAdaptor::GetRootActor
+ */
+ Dali::Actor GetRootActor();
+
+ /**
+ * @copydoc Dali::Toolkit::Physics::PhysicsAdaptor::BuildPickingRay
+ */
+ void BuildPickingRay(Dali::Vector3 origin, Dali::Vector3 direction, Dali::Vector3& rayFromWorld, Dali::Vector3& rayToWorld);
+
+ /**
+ * @copydoc Dali::Toolkit::Physics::PhysicsAdaptor::ProjectPoint
+ */
+ Dali::Vector3 ProjectPoint(Dali::Vector3 origin, Dali::Vector3 direction, float distance);
+
+ /**
+ * @copydoc Dali::Toolkit::Physics::PhysicsAdaptor::Queue
+ */
+ void Queue(std::function<void(void)> function);
+
+ /**
+ * @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:
+ 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;
+};
+
+} //namespace Internal
+
+inline Internal::PhysicsAdaptor& GetImplementation(Dali::Toolkit::Physics::PhysicsAdaptor& handle)
+{
+ DALI_ASSERT_ALWAYS(handle && "Physics adaptor handle is empty");
+ BaseObject& object = handle.GetBaseObject();
+ return static_cast<Internal::PhysicsAdaptor&>(object);
+}
+
+inline const Internal::PhysicsAdaptor& GetImplementation(const Dali::Toolkit::Physics::PhysicsAdaptor& handle)
+{
+ DALI_ASSERT_ALWAYS(handle && "Physics adaptor handle is empty");
+ const BaseObject& object = handle.GetBaseObject();
+ return static_cast<const Internal::PhysicsAdaptor&>(object);
+}
+
+} // namespace Dali::Toolkit::Physics
+
+#endif //DALI_TOOLKIT_PHYSICS_INTERNAL_ADAPTOR_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.
+ */
+
+#include "physics-debug-renderer.h"
+
+#include <dali/dali.h>
+#include "physics-adaptor-impl.h"
+
+using Dali::Degree;
+using Dali::Matrix;
+using Dali::Quaternion;
+using Dali::Radian;
+using Dali::Vector3;
+using Dali::Vector4;
+
+namespace
+{
+GLuint LoadShader(GLenum shaderType, const char* shaderSource)
+{
+ GLuint shader = glCreateShader(shaderType);
+ if(shader != 0)
+ {
+ glShaderSource(shader, 1, &shaderSource, NULL);
+ glCompileShader(shader);
+ GLint compiled = 0;
+ glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
+ if(compiled != GL_TRUE)
+ {
+ GLint infoLen = 0;
+ glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen);
+
+ if(infoLen > 0)
+ {
+ std::vector<char> logBuffer;
+ logBuffer.resize(infoLen + 1);
+ glGetShaderInfoLog(shader, infoLen, NULL, &logBuffer[0]);
+ fprintf(stderr, "%s\n", &logBuffer[0]);
+ fflush(stderr);
+
+ glDeleteShader(shader);
+ shader = 0;
+ }
+ }
+ }
+ return shader;
+}
+
+GLuint CreateProgram(const char* vertexSource, const char* fragmentSource)
+{
+ GLuint vertexShader = LoadShader(GL_VERTEX_SHADER, vertexSource);
+ if(!vertexShader)
+ {
+ return 0;
+ }
+ GLuint fragmentShader = LoadShader(GL_FRAGMENT_SHADER, fragmentSource);
+ if(!fragmentShader)
+ {
+ return 0;
+ }
+ GLuint program = glCreateProgram();
+ if(program)
+ {
+ glAttachShader(program, vertexShader);
+ glAttachShader(program, fragmentShader);
+ glLinkProgram(program);
+ GLint linkStatus = GL_FALSE;
+ glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
+ if(linkStatus != GL_TRUE)
+ {
+ GLint bufLength = 0;
+ glGetProgramiv(program, GL_INFO_LOG_LENGTH, &bufLength);
+ if(bufLength)
+ {
+ std::vector<char> logBuffer;
+ logBuffer.resize(bufLength + 1);
+ glGetProgramInfoLog(program, bufLength, NULL, &logBuffer[0]);
+ fprintf(stderr, "%s\n", &logBuffer[0]);
+ fflush(stderr);
+ }
+ glDeleteProgram(program);
+ program = 0;
+ }
+ }
+ return program;
+}
+} // namespace
+
+namespace Dali::Toolkit::Physics::Internal
+{
+std::unique_ptr<PhysicsDebugRenderer> PhysicsDebugRenderer::New(uint32_t width, uint32_t height, Dali::CameraActor camera, PhysicsAdaptor* adaptor)
+{
+ auto renderer = std::make_unique<PhysicsDebugRenderer>(width, height, camera, adaptor);
+ renderer->mRenderCallback = Dali::RenderCallback::New<PhysicsDebugRenderer>(renderer.get(), &PhysicsDebugRenderer::OnRender);
+ return renderer;
+}
+
+PhysicsDebugRenderer::PhysicsDebugRenderer(uint32_t width, uint32_t height, Dali::CameraActor camera, PhysicsAdaptor* adaptor)
+: mCamera(camera),
+ mWidth(width),
+ mHeight(height),
+ mAdaptor(*adaptor)
+{
+}
+
+bool PhysicsDebugRenderer::OnRender(const Dali::RenderCallbackInput& input)
+{
+ if(mState == State::INIT)
+ {
+ Setup();
+ mState = State::RENDER;
+ }
+ glViewport(0, 0, mWidth, mHeight);
+
+ RenderLines(input);
+
+ return false;
+}
+
+// Run on first invocation of callback
+void PhysicsDebugRenderer::Setup()
+{
+ PrepareShader();
+ mVertexLocation = glGetAttribLocation(mProgramId, "vertexPosition");
+ mVertexColourLocation = glGetAttribLocation(mProgramId, "vertexColour");
+ mProjectionLocation = glGetUniformLocation(mProgramId, "projection");
+ mModelViewLocation = glGetUniformLocation(mProgramId, "modelView");
+
+ glEnable(GL_DEPTH_TEST);
+ glViewport(0, 0, mWidth, mHeight);
+
+ glGenBuffers(1, &mBufferId);
+}
+
+void PhysicsDebugRenderer::UpdateWindowSize(Dali::Vector2 size)
+{
+ mWidth = size.width;
+ mHeight = size.height;
+}
+
+void PhysicsDebugRenderer::PrepareShader()
+{
+ static const char glVertexShader[] =
+ "attribute vec4 vertexPosition;\n"
+ "attribute vec3 vertexColour;\n"
+ "varying vec3 fragColour;\n"
+ "uniform mat4 projection;\n"
+ "uniform mat4 modelView;\n"
+ "void main()\n"
+ "{\n"
+ " gl_Position = projection * modelView * vertexPosition;\n"
+ " fragColour = vertexColour;\n"
+ "}\n";
+
+ static const char glFragmentShader[] =
+ "precision mediump float;\n"
+ "varying vec3 fragColour;\n"
+ "void main()\n"
+ "{\n"
+ " gl_FragColor = vec4(fragColour, 1.0);\n"
+ "}\n";
+
+ mProgramId = CreateProgram(glVertexShader, glFragmentShader);
+}
+
+void PhysicsDebugRenderer::RenderLines(const Dali::RenderCallbackInput& input)
+{
+ mModelViewMatrix.SetIdentity();
+ mProjectionMatrix = input.projection;
+
+ Matrix::Multiply(mModelViewMatrix, mModelViewMatrix, input.view);
+ glUseProgram(mProgramId);
+
+ // In theory, input.clippingBox should tell us the actor position in clip-space.
+ // But, it appears to be bugged.
+
+ glBindBuffer(GL_ARRAY_BUFFER, mBufferId);
+ glBufferData(GL_ARRAY_BUFFER, mLines.size() * sizeof(VertexLine), &mLines[0], GL_STATIC_DRAW);
+
+ glVertexAttribPointer(mVertexLocation, 3, GL_FLOAT, GL_FALSE, 24, 0);
+ glEnableVertexAttribArray(mVertexLocation);
+ glVertexAttribPointer(mVertexColourLocation, 3, GL_FLOAT, GL_FALSE, 24, reinterpret_cast<const void*>(12));
+ glEnableVertexAttribArray(mVertexColourLocation);
+ glUniformMatrix4fv(mProjectionLocation, 1, GL_FALSE, mProjectionMatrix.AsFloat());
+ glUniformMatrix4fv(mModelViewLocation, 1, GL_FALSE, mModelViewMatrix.AsFloat());
+
+ glDrawArrays(GL_LINES, 0, mLines.size());
+ mLines.clear();
+}
+
+void PhysicsDebugRenderer::drawLine(const btVector3& from, const btVector3& to, const btVector3& color)
+{
+ mLines.push_back(VertexLine{mAdaptor.TranslateFromPhysicsSpace(Vector3(from.x(), from.y(), from.z())),
+ Vector3(color.x(), color.y(), color.z())});
+ mLines.push_back(VertexLine{mAdaptor.TranslateFromPhysicsSpace(Vector3(to.x(), to.y(), to.z())), Vector3(color.x(), color.y(), color.z())});
+}
+
+void PhysicsDebugRenderer::drawLine(const btVector3& from, const btVector3& to, const btVector3& fromColor, const btVector3& toColor)
+{
+ mLines.push_back(VertexLine{mAdaptor.TranslateFromPhysicsSpace(Vector3(from.x(), from.y(), from.z())), Vector3(fromColor.x(), fromColor.y(), fromColor.z())});
+ mLines.push_back(VertexLine{mAdaptor.TranslateFromPhysicsSpace(Vector3(to.x(), to.y(), to.z())), Vector3(toColor.x(), toColor.y(), toColor.z())});
+}
+
+void PhysicsDebugRenderer::drawContactPoint(const btVector3& PointOnB, const btVector3& normalOnB, btScalar distance, int lifeTime, const btVector3& color)
+{
+}
+
+void PhysicsDebugRenderer::reportErrorWarning(const char* warningString)
+{
+}
+
+void PhysicsDebugRenderer::draw3dText(const btVector3& location, const char* textString)
+{
+}
+
+void PhysicsDebugRenderer::setDebugMode(int debugMode)
+{
+}
+
+int PhysicsDebugRenderer::getDebugMode() const
+{
+ return true;
+}
+
+} // 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 <GLES3/gl3.h>
+#include <LinearMath/btIDebugDraw.h>
+#include <dali/dali.h>
+
+using Dali::Actor;
+using Dali::CameraActor;
+using Dali::Geometry;
+using Dali::Renderer;
+using Dali::Shader;
+using Dali::TextureSet;
+
+namespace Dali::Toolkit::Physics::Internal
+{
+class PhysicsAdaptor;
+
+class PhysicsDebugRenderer : public btIDebugDraw
+{
+public:
+ // Creates and initializes a new renderer
+ static std::unique_ptr<PhysicsDebugRenderer> New(uint32_t width, uint32_t height, Dali::CameraActor camera, PhysicsAdaptor* adaptor);
+
+ /**
+ * Get the callback (for actor creation)
+ */
+ std::unique_ptr<Dali::RenderCallback>& GetCallback()
+ {
+ return mRenderCallback;
+ }
+
+ void UpdateWindowSize(Dali::Vector2 size);
+
+ /**
+ * Constructor.
+ * @param[in] width Width of the renderer - viewport
+ * @param[in] height Height of the renderer - viewport
+ */
+ PhysicsDebugRenderer(uint32_t width, uint32_t height, Dali::CameraActor camera, PhysicsAdaptor* adaptor);
+
+public: // Inherited from btIDebugDraw
+ // Assume this is called during FrameCallback (i.e. in update manager, rather than during render...)
+ // Generate stack of lines... render, then clear stack.
+ void drawLine(const btVector3& from, const btVector3& to, const btVector3& color) override;
+ void drawLine(const btVector3& from, const btVector3& to, const btVector3& fromColor, const btVector3& toColor) override;
+ void drawContactPoint(const btVector3& PointOnB, const btVector3& normalOnB, btScalar distance, int lifeTime, const btVector3& color) override;
+ void reportErrorWarning(const char* warningString) override;
+ void draw3dText(const btVector3& location, const char* textString) override;
+ void setDebugMode(int debugMode) override;
+ int getDebugMode() const override;
+
+private:
+ bool OnRender(const Dali::RenderCallbackInput& input);
+ void Setup();
+ void PrepareShader();
+ void RenderLines(const Dali::RenderCallbackInput& input);
+
+private:
+ CameraActor mCamera;
+ Renderer mDebugRenderer;
+ std::unique_ptr<Dali::RenderCallback> mRenderCallback;
+
+ enum class State
+ {
+ INIT,
+ RENDER
+ } mState{State::INIT};
+
+ struct VertexLine
+ {
+ Dali::Vector3 position;
+ Dali::Vector3 color;
+ };
+ std::vector<VertexLine> mLines;
+
+ Dali::Matrix mModelViewMatrix;
+ Dali::Matrix mViewMatrix;
+ Dali::Matrix mProjectionMatrix;
+ int mWidth;
+ int mHeight;
+ PhysicsAdaptor& mAdaptor;
+ GLint mVertexLocation;
+ GLint mVertexColourLocation;
+ GLint mProjectionLocation;
+ GLint mModelViewLocation;
+ GLuint mBufferId;
+ GLuint mProgramId;
+};
+
+} // 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-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>
+#include <dali/devel-api/common/stage-devel.h>
+#include <dali/devel-api/update/frame-callback-interface.h>
+
+namespace Dali::Toolkit::Physics::Internal
+{
+/**
+ * FrameCallback implementation. Will run the OnUpdate method.
+ */
+class FrameCallback : public Dali::FrameCallbackInterface
+{
+public:
+ /**
+ * Constructor
+ */
+ explicit FrameCallback(PhysicsWorld& physicsWorld)
+ : mPhysicsWorld(physicsWorld)
+ {
+ }
+
+private:
+ /**
+ * Called each frame.
+ * @param[in] updateProxy Used to set world matrix and size
+ * @param[in] elapsedSeconds Time since last frame
+ * @return Whether we should keep rendering.
+ */
+ bool Update(Dali::UpdateProxy& updateProxy, float elapsedSeconds) override
+ {
+ return mPhysicsWorld.OnUpdate(updateProxy, elapsedSeconds);
+ }
+
+private: // Member variables
+ PhysicsWorld& mPhysicsWorld;
+};
+
+using NativeWorld = btDiscreteDynamicsWorld*;
+
+std::unique_ptr<PhysicsWorld> PhysicsWorld::New(Dali::Actor rootActor, Dali::CallbackBase* updateCallback)
+{
+ std::unique_ptr<PhysicsWorld> world = std::make_unique<PhysicsWorld>(rootActor, updateCallback);
+ world->Initialize();
+ return world;
+}
+
+PhysicsWorld::PhysicsWorld(Dali::Actor rootActor, Dali::CallbackBase* updateCallback)
+: mUpdateCallback(updateCallback),
+ mRootActor(rootActor)
+{
+ Initialize();
+}
+
+void PhysicsWorld::Initialize(/*void* dynamicsWorld*/)
+{
+ // @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);
+
+ // Automatically start the frame callback. This means everything should
+ // be accessed with a mutex lock, which is automatically locked when
+ // ScopedAccessor is used.
+ mFrameCallback = std::make_unique<FrameCallback>(*this);
+ Dali::DevelStage::AddFrameCallback(Dali::Stage::GetCurrent(), *mFrameCallback, mRootActor);
+ 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);
+
+ 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::Mutex& PhysicsWorld::GetMutex()
+{
+ return mMutex;
+}
+
+bool PhysicsWorld::OnUpdate(Dali::UpdateProxy& updateProxy, float elapsedSeconds)
+{
+ Dali::Mutex::ScopedLock lock(mMutex);
+
+ // Process command queue
+ if(mNotifySyncPoint != Dali::UpdateProxy::INVALID_SYNC &&
+ mNotifySyncPoint == updateProxy.PopSyncPoint())
+ {
+ do
+ {
+ commandQueue.front()(); // Execute the queued methods
+ commandQueue.pop();
+ } while(!commandQueue.empty());
+
+ mNotifySyncPoint = Dali::UpdateProxy::INVALID_SYNC;
+ }
+
+ // Perform as many integration steps as needed to handle elapsed time
+ static float frameTime = 0;
+ frameTime += elapsedSeconds;
+ do
+ {
+ Integrate(mPhysicsTimeStep);
+ frameTime -= mPhysicsTimeStep;
+ } while(frameTime > 0);
+
+ // Update the corresponding actors to their physics spaces
+ if(mUpdateCallback)
+ {
+ Dali::CallbackBase::Execute(*mUpdateCallback, &updateProxy); // Don't care about actor update return
+ }
+
+ // @todo Check physics world to see if everything is at rest
+ 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;
+}
+
+float PhysicsWorld::GetTimestep()
+{
+ return mPhysicsTimeStep;
+}
+
+void PhysicsWorld::Queue(std::function<void(void)> function)
+{
+ if(!mMutex.IsLocked()) // Annoyingly, the dali mutex scoped lock doesn't prevent relocking in the same thread.
+ {
+ Dali::Mutex::ScopedLock lock(mMutex);
+ commandQueue.push(function);
+ }
+ else
+ {
+ commandQueue.push(function);
+ }
+}
+
+void PhysicsWorld::CreateSyncPoint()
+{
+ mNotifySyncPoint = Dali::DevelStage::NotifyFrameCallback(Dali::Stage::GetCurrent(), *mFrameCallback);
+}
+
+inline btVector3 ConvertVector(Dali::Vector3 vector)
+{
+ return btVector3(vector.x, vector.y, vector.z);
+}
+
+Dali::Any PhysicsWorld::HitTest(Dali::Vector3 rayFromWorld, Dali::Vector3 rayToWorld, Dali::Vector3& localPivot, float& distanceFromCamera)
+{
+ btRigidBody* hitBody{nullptr};
+
+ btVector3 origin = ConvertVector(rayFromWorld);
+ btVector3 end = ConvertVector(rayToWorld);
+ btCollisionWorld::ClosestRayResultCallback rayResultCallback(origin, end);
+ rayResultCallback.m_flags |= btTriangleRaycastCallback::kF_UseGjkConvexCastRaytest;
+
+ mDynamicsWorld->rayTest(origin, end, rayResultCallback);
+ if(rayResultCallback.hasHit())
+ {
+ auto pickPos = rayResultCallback.m_hitPointWorld;
+ btRigidBody* body = (btRigidBody*)btRigidBody::upcast(rayResultCallback.m_collisionObject);
+ if(body)
+ {
+ if(!(body->isStaticObject() || body->isKinematicObject()))
+ {
+ hitBody = body; // Found a dynamic body.
+ distanceFromCamera = (pickPos - origin).length();
+
+ btVector3 pivot = body->getCenterOfMassTransform().inverse() * pickPos;
+ localPivot.x = pivot.x();
+ localPivot.y = pivot.y();
+ localPivot.z = pivot.z();
+ }
+ }
+ }
+ Dali::Any bodyPtr;
+ if(hitBody)
+ {
+ bodyPtr = hitBody;
+ }
+
+ return bodyPtr;
+}
+
+void PhysicsWorld::SetIntegrationState(Physics::PhysicsAdaptor::IntegrationState state)
+{
+ mPhysicsIntegrateState = state;
+}
+
+Physics::PhysicsAdaptor::IntegrationState PhysicsWorld::GetIntegrationState()
+{
+ return mPhysicsIntegrateState;
+}
+
+void PhysicsWorld::SetDebugState(Physics::PhysicsAdaptor::DebugState state)
+{
+ mPhysicsDebugState = state;
+}
+
+Physics::PhysicsAdaptor::DebugState PhysicsWorld::GetDebugState()
+{
+ return mPhysicsDebugState;
+}
+
+} // namespace Dali::Toolkit::Physics::Internal
--- /dev/null
+#ifndef DALI_TOOLKIT_PHYSICS_INTERNAL_PHYSICS_WORLD_H
+#define DALI_TOOLKIT_PHYSICS_INTERNAL_PHYSICS_WORLD_H
+
+/*
+ * 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/public-api/physics-adaptor.h>
+
+#include <btBulletDynamicsCommon.h>
+#include <functional>
+#include <queue>
+
+namespace Dali::Toolkit::Physics::Internal
+{
+class PhysicsWorld;
+class FrameCallback;
+
+class PhysicsWorld /* : public BaseObject */
+{
+public:
+ static std::unique_ptr<PhysicsWorld> New(Dali::Actor rootActor, Dali::CallbackBase* updateCallback);
+
+ PhysicsWorld(Dali::Actor rootActor, Dali::CallbackBase* updateCallback);
+ ~PhysicsWorld();
+
+ void Initialize(/*void* dynamicsWorld*/);
+
+ Dali::Any GetNative();
+
+ /**
+ * Set how long the integration should take.
+ * @param[in] timestep The length of time that the physics integration should take.
+ */
+ void SetTimestep(float timestep);
+
+ /**
+ * Get the current physics integration timestep
+ * @return the current physics integration timestep
+ */
+ float GetTimestep();
+
+ /**
+ * 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);
+
+ /**
+ * 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.
+ *
+ * @param[in] None
+ */
+ void CreateSyncPoint();
+
+ /**
+ * 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);
+
+ /**
+ * @copydoc Dali::Toolkit::Physics::PhysicsAdaptor::SetIntegrationState
+ */
+ void SetIntegrationState(Physics::PhysicsAdaptor::IntegrationState state);
+
+ /**
+ * @copydoc Dali::Toolkit::Physics::PhysicsAdaptor::GetIntegrationState
+ */
+ Physics::PhysicsAdaptor::IntegrationState GetIntegrationState();
+
+ /**
+ * @copydoc Dali::Toolkit::Physics::PhysicsAdaptor::SetDebugState
+ */
+ void SetDebugState(Physics::PhysicsAdaptor::DebugState state);
+
+ /**
+ * @copydoc Dali::Toolkit::Physics::PhysicsAdaptor::GetDebugState
+ */
+ Physics::PhysicsAdaptor::DebugState GetDebugState();
+
+public:
+ Dali::Mutex& GetMutex(); // Only for use by adaptor in creating scoped accessor
+
+ 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};
+
+ 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};
+
+ Physics::PhysicsAdaptor::IntegrationState mPhysicsIntegrateState{Physics::PhysicsAdaptor::IntegrationState::ON};
+ Physics::PhysicsAdaptor::DebugState mPhysicsDebugState{Physics::PhysicsAdaptor::DebugState::OFF};
+};
+
+} // namespace Dali::Toolkit::Physics::Internal
+
+#endif //DALI_TOOLKIT_PHYSICS_INTERNAL_PHYSICS_WORLD_H
--- /dev/null
+set(physics3d_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(physics3d_public_api_header_files
+ ${physics3d_public_api_dir}/physics-actor.h
+ ${physics3d_public_api_dir}/physics-adaptor.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/public-api/physics-actor.h>
+
+// Internal headers
+#include <dali-physics/internal/physics-actor-impl.h>
+#include <dali-physics/internal/physics-adaptor-impl.h>
+
+namespace Dali::Toolkit::Physics
+{
+PhysicsActor::PhysicsActor() = default;
+PhysicsActor::~PhysicsActor() = default;
+PhysicsActor::PhysicsActor(const PhysicsActor& handle) = default;
+PhysicsActor::PhysicsActor(PhysicsActor&& rhs) noexcept = default;
+PhysicsActor& PhysicsActor::operator=(const PhysicsActor& handle) = default;
+PhysicsActor& PhysicsActor::operator=(PhysicsActor&& handle) noexcept = default;
+
+PhysicsActor PhysicsActor::New(Dali::Actor actor, Dali::Any body, PhysicsAdaptor adaptor)
+{
+ Dali::Toolkit::Physics::Internal::PhysicsActorPtr internal = Internal::PhysicsActor::New(actor, body, GetImplementation(adaptor));
+ return PhysicsActor(internal.Get());
+}
+
+PhysicsActor PhysicsActor::DownCast(BaseHandle handle)
+{
+ return PhysicsActor(dynamic_cast<Dali::Toolkit::Physics::Internal::PhysicsActor*>(handle.GetObjectPtr()));
+}
+
+uint32_t PhysicsActor::GetId() const
+{
+ return GetImplementation(*this).GetId();
+}
+
+Dali::Any PhysicsActor::GetBody() const
+{
+ return GetImplementation(*this).GetBody();
+}
+
+void PhysicsActor::AsyncSetPhysicsPosition(Dali::Vector3 actorPosition)
+{
+ GetImplementation(*this).AsyncSetPhysicsPosition(actorPosition);
+}
+
+void PhysicsActor::AsyncSetPhysicsRotation(Dali::Quaternion actorRotation)
+{
+ GetImplementation(*this).AsyncSetPhysicsRotation(actorRotation);
+}
+
+Dali::Vector3 PhysicsActor::GetPhysicsPosition() const
+{
+ return GetImplementation(*this).GetPhysicsPosition();
+}
+
+Dali::Quaternion PhysicsActor::GetPhysicsRotation() const
+{
+ return GetImplementation(*this).GetPhysicsRotation();
+}
+
+Dali::Vector3 PhysicsActor::GetActorPosition() const
+{
+ return GetImplementation(*this).GetActorPosition();
+}
+
+Dali::Quaternion PhysicsActor::GetActorRotation() const
+{
+ return GetImplementation(*this).GetActorRotation();
+}
+
+PhysicsActor::PhysicsActor(Internal::PhysicsActor* impl)
+: BaseHandle(impl)
+{
+}
+
+} // namespace Dali::Toolkit::Physics
--- /dev/null
+#ifndef DALI_TOOLKIT_PHYSICS_ACTOR_H
+#define DALI_TOOLKIT_PHYSICS_ACTOR_H
+
+/*
+ * 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.
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/actors/actor.h>
+#include <dali/public-api/object/any.h>
+#include <dali/public-api/object/base-handle.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/dali-toolkit-common.h>
+
+namespace Dali::Toolkit::Physics
+{
+class PhysicsAdaptor;
+
+namespace Internal
+{
+class PhysicsActor;
+}
+
+/**
+ * Class to associate a physics body (such as btRigidBody*) with a DALi
+ * actor for rendering.
+ *
+ * This object offers methods to modify basic physics properties
+ * asynchronously, that is, on the Update thread. It is also possible
+ * for the developer to queue other physics functions on the body by
+ * using PhysicsWorld::Queue() and passing in a lambda that captures the
+ * body.
+ *
+ * For example:
+ * btRigidBody* body = physicsActor.GetBody().Get<btRigidBody*>();
+ * mPhysicsImpl.Queue([body](){ body->clearForces(); });
+ * This enables the developer to synchronize setting physics properties
+ * and setting DALi actor properties.
+ */
+class DALI_TOOLKIT_API PhysicsActor : public Dali::BaseHandle
+{
+public:
+ PhysicsActor();
+ ~PhysicsActor();
+ PhysicsActor(const PhysicsActor& handle);
+ PhysicsActor(PhysicsActor&& rhs) noexcept;
+ PhysicsActor& operator=(const PhysicsActor& handle);
+ PhysicsActor& operator=(PhysicsActor&& handle) noexcept;
+
+ /**
+ * New method.
+ * @SINCE_2.2.40
+ *
+ * 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
+ * rotation in that space. The Actor is used to render that object in
+ * DALi space.
+ *
+ * @note This object only stores the actor ID, which is used
+ * internally in the FrameCallback. It is up to the caller to ensure
+ * there is a reference to the actor (e.g. by parenting into the scene)
+ *
+ * @note This API is used internally, and is of little benefit to the developer.
+ *
+ * @param[in] actor The DALi actor used to render this object
+ * @param[in] body The physics body used in the physics simulation
+ * @param[in] adaptor The physics adaptor to use. @todo remove?
+ */
+ static PhysicsActor New(Dali::Actor actor, Dali::Any body, PhysicsAdaptor adaptor);
+
+ /**
+ * @brief Downcasts a handle to PhysicsActor handle.
+ *
+ * If handle points to an PhysicsActor object, the downcast produces valid handle.
+ * If not, the returned handle is left uninitialized.
+ *
+ * @SINCE_2.2.40
+ * @param[in] handle to an object
+ * @return handle to a PhysicsActor object or an uninitialized handle
+ */
+ static PhysicsActor DownCast(BaseHandle handle);
+
+ /**
+ * @brief Get the actor ID of the associated actor.
+ */
+ uint32_t GetId() const;
+
+ /**
+ * 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,
+ * for example:
+ * btRigidBody* body = actor.GetBody().Get<btRigidBody*>();
+ *
+ * @note Please ensure to get a scoped accessor first to avoid modifying
+ * physics properties during integration step, or use the Async methods
+ * or the Queue.
+ */
+ Dali::Any GetBody() const;
+
+ /**
+ * Queue a method to set the position on the associated physics body
+ * in the update thread before the next integration.
+ * @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
+ * in the update thread before the next integration.
+ * @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.
+ * @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.
+ * @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.
+ * @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.
+ * @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
+ */
+ explicit DALI_INTERNAL PhysicsActor(Internal::PhysicsActor* impl);
+ /// @endcond
+};
+
+} // namespace Dali::Toolkit::Physics
+
+#endif //DALI_TOOLKIT_PHYSICS_ACTOR_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/public-api/physics-adaptor.h>
+
+// Internal headers
+#include <dali-physics/internal/physics-actor-impl.h>
+#include <dali-physics/internal/physics-adaptor-impl.h>
+#include <dali-physics/public-api/physics-actor.h>
+
+namespace Dali::Toolkit::Physics
+{
+PhysicsAdaptor::PhysicsAdaptor() = default;
+
+PhysicsAdaptor::~PhysicsAdaptor() = default;
+
+PhysicsAdaptor::PhysicsAdaptor(const PhysicsAdaptor& handle) = default;
+
+PhysicsAdaptor::PhysicsAdaptor(PhysicsAdaptor&& rhs) noexcept = default;
+
+PhysicsAdaptor& PhysicsAdaptor::operator=(const PhysicsAdaptor& handle) = default;
+
+PhysicsAdaptor& PhysicsAdaptor::operator=(PhysicsAdaptor&& handle) noexcept = default;
+
+PhysicsAdaptor PhysicsAdaptor::New(const Dali::Matrix& transform, Uint16Pair size)
+{
+ Internal::PhysicsAdaptorPtr internal = Internal::PhysicsAdaptor::New(transform, size);
+ return PhysicsAdaptor(internal.Get());
+}
+
+PhysicsAdaptor PhysicsAdaptor::DownCast(BaseHandle handle)
+{
+ return PhysicsAdaptor(dynamic_cast<Dali::Toolkit::Physics::Internal::PhysicsAdaptor*>(handle.GetObjectPtr()));
+}
+
+void PhysicsAdaptor::SetTimestep(float timestep)
+{
+ GetImplementation(*this).SetTimestep(timestep);
+}
+
+float PhysicsAdaptor::GetTimestep()
+{
+ return GetImplementation(*this).GetTimestep();
+}
+
+PhysicsAdaptor::ScopedPhysicsAccessorPtr PhysicsAdaptor::GetPhysicsAccessor()
+{
+ return GetImplementation(*this).GetPhysicsAccessor();
+}
+
+Dali::Layer PhysicsAdaptor::CreateDebugLayer(Dali::Window window)
+{
+ return GetImplementation(*this).CreateDebugLayer(window);
+}
+
+Dali::Vector3 PhysicsAdaptor::TranslateToPhysicsSpace(Dali::Vector3 vector)
+{
+ return GetImplementation(*this).TranslateToPhysicsSpace(vector);
+}
+
+Dali::Quaternion PhysicsAdaptor::TranslateToPhysicsSpace(Dali::Quaternion rotation)
+{
+ return GetImplementation(*this).TranslateToPhysicsSpace(rotation);
+}
+
+Dali::Vector3 PhysicsAdaptor::TranslateFromPhysicsSpace(Dali::Vector3 vector)
+{
+ return GetImplementation(*this).TranslateFromPhysicsSpace(vector);
+}
+
+Dali::Vector3 PhysicsAdaptor::ConvertVectorToPhysicsSpace(Dali::Vector3 vector)
+{
+ return GetImplementation(*this).ConvertVectorToPhysicsSpace(vector);
+}
+
+Dali::Vector3 PhysicsAdaptor::ConvertVectorFromPhysicsSpace(Dali::Vector3 vector)
+{
+ return GetImplementation(*this).ConvertVectorFromPhysicsSpace(vector);
+}
+
+void PhysicsAdaptor::SetTransformAndSize(const Dali::Matrix& transform, Uint16Pair size)
+{
+ GetImplementation(*this).SetTransformAndSize(transform, size);
+}
+
+void PhysicsAdaptor::SetIntegrationState(Physics::PhysicsAdaptor::IntegrationState state)
+{
+ GetImplementation(*this).SetIntegrationState(state);
+}
+
+Physics::PhysicsAdaptor::IntegrationState PhysicsAdaptor::GetIntegrationState()
+{
+ return GetImplementation(*this).GetIntegrationState();
+}
+
+void PhysicsAdaptor::SetDebugState(Physics::PhysicsAdaptor::DebugState state)
+{
+ GetImplementation(*this).SetDebugState(state);
+}
+
+Physics::PhysicsAdaptor::DebugState PhysicsAdaptor::GetDebugState()
+{
+ return GetImplementation(*this).GetDebugState();
+}
+
+PhysicsActor PhysicsAdaptor::AddActorBody(Dali::Actor actor, Dali::Any body)
+{
+ Internal::PhysicsActorPtr physicsActor = GetImplementation(*this).AddActorBody(actor, body);
+ return PhysicsActor(physicsActor.Get());
+}
+
+PhysicsActor PhysicsAdaptor::GetPhysicsActor(Dali::Any body)
+{
+ Internal::PhysicsActorPtr physicsActor = GetImplementation(*this).GetPhysicsActor(body);
+ return PhysicsActor(physicsActor.Get());
+}
+
+Dali::Actor PhysicsAdaptor::GetRootActor()
+{
+ return GetImplementation(*this).GetRootActor();
+}
+
+void PhysicsAdaptor::BuildPickingRay(Dali::Vector3 origin, Dali::Vector3 direction, Dali::Vector3& rayFromWorld, Dali::Vector3& rayToWorld)
+{
+ GetImplementation(*this).BuildPickingRay(origin, direction, rayFromWorld, rayToWorld);
+}
+
+Dali::Vector3 PhysicsAdaptor::ProjectPoint(Dali::Vector3 origin, Dali::Vector3 direction, float distance)
+{
+ return GetImplementation(*this).ProjectPoint(origin, direction, distance);
+}
+
+void PhysicsAdaptor::Queue(std::function<void(void)> function)
+{
+ GetImplementation(*this).Queue(function);
+}
+
+void PhysicsAdaptor::CreateSyncPoint()
+{
+ GetImplementation(*this).CreateSyncPoint();
+}
+
+PhysicsAdaptor::PhysicsAdaptor(Internal::PhysicsAdaptor* impl)
+: BaseHandle(impl)
+{
+}
+
+} // namespace Dali::Toolkit::Physics
--- /dev/null
+#ifndef DALI_TOOLKIT_PHYSICS_ADAPTOR_H
+#define DALI_TOOLKIT_PHYSICS_ADAPTOR_H
+
+/*
+ * 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
+#include <dali/public-api/actors/actor.h>
+#include <dali/public-api/adaptor-framework/window.h>
+#include <dali/public-api/object/any.h>
+#include <dali/public-api/object/base-handle.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/dali-toolkit-common.h>
+
+namespace Dali::Toolkit::Physics
+{
+class PhysicsActor;
+
+namespace Internal
+{
+class PhysicsAdaptor;
+class PhysicsWorld;
+} // namespace Internal
+
+/**
+ * Adaptor to manage access to the physics world and pairing actors and physics
+ * bodies, plus some translation methods to/from the physics space and dali space.
+ *
+ * Also manages a debug renderer that may utilize the physics engine debug.
+ * It is up to the developer to retrieve the root actor and parent it into the scene.
+ */
+class DALI_TOOLKIT_API PhysicsAdaptor : public BaseHandle
+{
+public:
+ enum class IntegrationState
+ {
+ OFF,
+ ON
+ };
+ enum class DebugState
+ {
+ OFF,
+ ON
+ };
+
+ /**
+ * 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.
+ *
+ * When it goes out of scope, the mutex is unlocked, and the integration step
+ * can resume.
+ */
+ struct ScopedPhysicsAccessor
+ {
+ 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:
+ * auto accessor = PhysicsAdaptor.GetPhysicsAccessor();
+ * auto bulletWorld = accessor->GetNative().Get<btDiscreteDynamiscWorld*>();
+ */
+ Dali::Any GetNative();
+
+ /**
+ * 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);
+
+ // Not copyable
+ ScopedPhysicsAccessor(ScopedPhysicsAccessor&) = delete;
+ const ScopedPhysicsAccessor& operator=(const ScopedPhysicsAccessor&) = delete;
+
+ /**
+ * Destructor
+ */
+ ~ScopedPhysicsAccessor();
+
+ private:
+ ScopedPhysicsAccessor(Internal::PhysicsWorld& world);
+ friend Internal::PhysicsAdaptor;
+
+ struct Impl;
+ Impl* mImpl;
+ };
+
+ PhysicsAdaptor();
+ ~PhysicsAdaptor();
+ PhysicsAdaptor(const PhysicsAdaptor& handle);
+ PhysicsAdaptor(PhysicsAdaptor&& rhs) noexcept;
+ PhysicsAdaptor& operator=(const PhysicsAdaptor& handle);
+ PhysicsAdaptor& operator=(PhysicsAdaptor&& handle) noexcept;
+
+ /**
+ * Initialize the physics system.
+ *
+ * @todo Consider allowing developer to create the physics world and pass it in here.
+ *
+ * @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
+ */
+ static PhysicsAdaptor New(const Dali::Matrix& transform, Uint16Pair size);
+
+ /**
+ * @brief Downcasts a handle to PhysicsAdaptor handle.
+ *
+ * If handle points to an PhysicsAdaptor object, the downcast produces valid handle.
+ * If not, the returned handle is left uninitialized.
+ *
+ * @SINCE_2.2.40
+ * @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.
+ * @param[in] timestep The length of time that the physics integration should take.
+ */
+ void SetTimestep(float timestep);
+
+ /**
+ * Get the current physics integration timestep
+ * @return the current physics integration timestep
+ */
+ float GetTimestep();
+
+ /**
+ * 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.
+ *
+ * When the pointer goes out of scope, the mutex is unlocked and the physics world
+ * can run again.
+ */
+ using ScopedPhysicsAccessorPtr = std::unique_ptr<PhysicsAdaptor::ScopedPhysicsAccessor>;
+ ScopedPhysicsAccessorPtr GetPhysicsAccessor();
+
+ /**
+ * Create a layer & debug renderer
+ * The debug renderer may utilize the debug features of the native physics
+ * engine.
+ *
+ * @param[in] window The window to draw in (requires camera)
+ */
+ Dali::Layer CreateDebugLayer(Dali::Window window);
+
+ /**
+ * Converts a point in RootActor local coords (e.g. gesture)
+ * into physics space coords.
+ * @param vector The point to convert
+ * @return The converted point
+ */
+ Dali::Vector3 TranslateToPhysicsSpace(Dali::Vector3 vector);
+
+ /**
+ * Convert a rotation in DALi coordinate system into physics space.
+ * @param[in] rotation The rotation to convert
+ * @return the converted rotation.
+ */
+ Dali::Quaternion TranslateToPhysicsSpace(Dali::Quaternion rotation);
+
+ /**
+ * Converts a point in physics space coords.
+ * into RootActor local coords
+ * @param vector The point to convert
+ * @return The converted point
+ */
+ Dali::Vector3 TranslateFromPhysicsSpace(Dali::Vector3 vector);
+
+ /**
+ * Convert a rotation in physics coordinate system into DALi space.
+ * @param[in] rotation The rotation to convert
+ * @return the converted rotation.
+ */
+ Dali::Quaternion TranslateFromPhysicsSpace(Dali::Quaternion rotation);
+
+ /**
+ * Converts a vector (not a point) in DALi space into physics space.
+ * @param vector The vector to convert
+ * @return The converted vector
+ */
+ Dali::Vector3 ConvertVectorToPhysicsSpace(Dali::Vector3 vector);
+
+ /**
+ * Converts a vector (not a point) in physics space to DALi space
+ * @param vector The vector to convert
+ * @return The converted vector
+ */
+ Dali::Vector3 ConvertVectorFromPhysicsSpace(Dali::Vector3 vector);
+
+ /**
+ * Set up the transform from world space to physics space
+ * @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.
+ * @note This is ON by default
+ * @param[in] state the new integration state
+ */
+ void SetIntegrationState(IntegrationState state);
+
+ /**
+ * Get the integration state.
+ * @return the new integration state
+ */
+ IntegrationState GetIntegrationState();
+
+ /**
+ * Set the debug state. 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.
+ * @return the new debug state
+ */
+ DebugState GetDebugState();
+
+ /**
+ * Add an actor / body pair.
+ * @pre It's expected that the client has added the body to the physics world.
+ *
+ * @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
+ * @param[in] body The physics body
+ * @return the associated physics actor
+ */
+ PhysicsActor GetPhysicsActor(Dali::Any body);
+
+ /**
+ * Get the root actor (which holds all the actor/body pairs)
+ */
+ Dali::Actor GetRootActor();
+
+ /**
+ * Convert DALi touch point into a picking ray in the physics world.
+ *
+ * These can then be used to hit test the PhysicsWorld
+ *
+ * @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
+ *
+ * Example:
+ * OnTouched(Dali::Actor actor, Dali::TouchEvent& touch)
+ * {
+ * ..
+ * Vector3 origin, direction;
+ * Dali::HitTestAlgorithm::BuildPickingRay(renderTask, touch.GetScreenPosition(0), origin, direction);
+ * btVector3 rayFromWorld, rayToWorld;
+ * physicsAdaptor.BuildPickingRay(origin, direction, rayFromWorld, rayToWorld);
+ * auto scopedAccessor = physicsAdaptor.GetPhysicsAccessor();
+ * body = scopedAccessor->Get().HitTest(rayFromWorld, rayToWorld, ..);
+ * }
+ */
+ 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
+ * the direction vector (in DALi space), and return the projected
+ * point in Physics space.
+ *
+ * @param[in] origin Origin in DALi world space
+ * @param[in] direction Direction in DALi world space
+ * @param[in] distance Distance along the direction vector
+ * @return the projected point, converted to the Physics space.
+ */
+ 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.
+ *
+ * @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
+ * will very likely cause the update thread to crash.
+ */
+ void Queue(std::function<void(void)> function);
+
+ /**
+ * 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.
+ *
+ * @param[in] None
+ */
+ void CreateSyncPoint();
+
+public: // Not intended for developer use
+ /// @cond internal
+ /**
+ * @note Not intented for application developers
+ */
+ explicit DALI_INTERNAL PhysicsAdaptor(Internal::PhysicsAdaptor* impl);
+ /// @endcond
+};
+
+} // namespace Dali::Toolkit::Physics
+
+#endif //DALI_TOOLKIT_PHYSICS_ADAPTOR_H
cameraParameters.zNear = ortho.mZNear;
cameraParameters.zFar = ortho.mZFar;
}
+
+ cameraParameters.name = std::string(camera.mName);
}
void ConvertNode(gltf2::Node const& node, const Index gltfIndex, Index parentIndex, ConversionContext& context, bool isMRendererModel)
} // namespace Gltf2Util
-} // namespace Dali::Scene3D::Loader::Internal
\ No newline at end of file
+} // namespace Dali::Scene3D::Loader::Internal
bool CameraParameters::ConfigureCamera(CameraActor& camera, bool invertY) const
{
+ camera[Actor::Property::NAME] = name;
+
if(isPerspective)
{
if(Dali::Equals(zNear, gltf2::UNDEFINED_FLOAT_VALUE) ||
return true;
}
-} // namespace Dali::Scene3D::Loader
\ No newline at end of file
+} // namespace Dali::Scene3D::Loader
#include <dali/public-api/math/degree.h>
#include <dali/public-api/math/matrix.h>
#include <dali/public-api/math/vector3.h>
+#include <string>
namespace Dali
{
{
struct DALI_SCENE3D_API CameraParameters
{
+ std::string name;
+
// TODO : Is these default value has is meaning?
Matrix matrix = Matrix::IDENTITY;
float orthographicSize = 1.f;
%endif
%defattr(-,root,root,-)
%{_libdir}/libchipmunk.so*
+#%{_libdir}/libdali2-physics-2d.so*
%license LICENSE
%files -n %{dali2_physics2d}-devel
%defattr(-,root,root,-)
+%{_includedir}/dali-physics/public-api/*
%{_includedir}/chipmunk/*
%{_libdir}/pkgconfig/dali2-physics-2d.pc
%{_libdir}/pkgconfig/chipmunk2d.pc
%endif
%defattr(-,root,root,-)
%{_libdir}/libbullet3.so*
+%{_libdir}/libdali2-physics-3d.so*
%license LICENSE
%files -n %{dali2_physics3d}-devel
%defattr(-,root,root,-)
+%{_includedir}/dali-physics/public-api/*
%{_includedir}/bullet/*
%{_libdir}/pkgconfig/dali2-physics-3d.pc
%{_libdir}/pkgconfig/bullet3.pc
-