CameraTransition in SceneView 18/315318/24
authorSeungho Baek <sbsh.baek@samsung.com>
Tue, 30 Jul 2024 06:17:41 +0000 (15:17 +0900)
committerSeungho Baek <sbsh.baek@samsung.com>
Fri, 16 Aug 2024 03:58:59 +0000 (12:58 +0900)
 - When StartCameraTransition is called, it is registered in Processor.
 - Processor creates and requests camera transition

Change-Id: Ia5a2ea818c7ace947ff3a01d01ad98de9ce2c92e
Signed-off-by: Seungho Baek <sbsh.baek@samsung.com>
automated-tests/src/dali-scene3d/utc-Dali-SceneView.cpp
dali-scene3d/internal/controls/scene-view/scene-view-impl.cpp
dali-scene3d/internal/controls/scene-view/scene-view-impl.h
dali-scene3d/public-api/controls/scene-view/scene-view.cpp
dali-scene3d/public-api/controls/scene-view/scene-view.h

index cd35ed418f7dc7d8fe57846e0127b2a28923a734..cef724d1c42797cc3869d299a8b6afb7aefbdb2a 100644 (file)
@@ -25,6 +25,7 @@
 
 #include <dali-scene3d/public-api/controls/model/model.h>
 #include <dali-scene3d/public-api/controls/scene-view/scene-view.h>
+#include <dali/devel-api/actors/camera-actor-devel.h>
 
 
 using namespace Dali;
@@ -1517,11 +1518,11 @@ int UtcDaliSceneViewSelectCamera(void)
   DALI_TEST_CHECK(camera1.GetParent());
   DALI_TEST_EQUALS(camera1.GetParent(), camera2.GetParent(), TEST_LOCATION);
 
+  view.SelectCamera("camera1");
   Scene3D::Model model = Scene3D::Model::New();
   view.Add(model);
   model.Add(camera1);
   DALI_TEST_EQUALS(camera1.GetParent(), model, TEST_LOCATION);
-  view.SelectCamera("camera1");
   DALI_TEST_EQUALS(camera1, view.GetSelectedCamera(), TEST_LOCATION);
   DALI_TEST_CHECK(camera1.GetParent());
   DALI_TEST_CHECK(camera2.GetParent());
@@ -1543,5 +1544,405 @@ int UtcDaliSceneViewSelectCamera(void)
 
   DALI_TEST_NOT_EQUALS(camera1, view.GetSelectedCamera(), 0.01f, TEST_LOCATION);
 
+  END_TEST;
+}
+
+
+// Functor to test whether a Finish signal is emitted
+struct TransitionFinishCheck
+{
+  TransitionFinishCheck(bool& signalReceived)
+  : mSignalReceived(signalReceived)
+  {
+  }
+
+  void operator()(Scene3D::SceneView& sceneView)
+  {
+    mSignalReceived = true;
+  }
+
+  void Reset()
+  {
+    mSignalReceived = false;
+  }
+
+  void CheckSignalReceived()
+  {
+    if(!mSignalReceived)
+    {
+      tet_printf("Expected Finish signal was not received\n");
+      tet_result(TET_FAIL);
+    }
+    else
+    {
+      tet_result(TET_PASS);
+    }
+  }
+
+  void CheckSignalNotReceived()
+  {
+    if(mSignalReceived)
+    {
+      tet_printf("Unexpected Finish signal was received\n");
+      tet_result(TET_FAIL);
+    }
+    else
+    {
+      tet_result(TET_PASS);
+    }
+  }
+
+  bool& mSignalReceived; // owned by individual tests
+};
+
+int UtcDaliSceneViewCameraTransitionFail(void)
+{
+  ToolkitTestApplication application;
+
+  Scene3D::SceneView view = Scene3D::SceneView::New();
+  application.GetScene().Add(view);
+
+  CameraActor camera1 = CameraActor::New3DCamera();
+  camera1.SetProperty(Dali::Actor::Property::NAME, "camera1");
+  view.AddCamera(camera1);
+  DALI_TEST_CHECK(!camera1.GetParent());
+  view.SelectCamera("camera1");
+  DALI_TEST_CHECK(camera1.GetParent());
+  DALI_TEST_EQUALS(camera1, view.GetSelectedCamera(), TEST_LOCATION);
+
+  camera1.SetProperty(Dali::Actor::Property::POSITION, Vector3::ONE * -50.0f);
+  view.Add(camera1);
+
+  bool                  signalReceived(false);
+  TransitionFinishCheck finishCheck(signalReceived);
+  view.CameraTransitionFinishedSignal().Connect(&application, finishCheck);
+
+  view.StartCameraTransition("camera1", 1.0f);
+
+  application.SendNotification();
+  application.Render(500);
+  application.SendNotification();
+
+  // We didn't expect the animation to finish yet
+  finishCheck.CheckSignalNotReceived();
+
+  application.SendNotification();
+  application.Render(600);
+  application.SendNotification();
+
+  finishCheck.CheckSignalNotReceived();
+
+  CameraActor finalCamera = view.GetSelectedCamera();
+  DALI_TEST_EQUALS(finalCamera, camera1, TEST_LOCATION);
+
+  END_TEST;
+}
+
+int UtcDaliSceneViewCameraChangeDuringTransition(void)
+{
+  ToolkitTestApplication application;
+
+  Scene3D::SceneView view = Scene3D::SceneView::New();
+  application.GetScene().Add(view);
+
+  CameraActor camera1 = CameraActor::New3DCamera();
+  camera1.SetProperty(Dali::Actor::Property::NAME, "camera1");
+  view.AddCamera(camera1);
+  DALI_TEST_CHECK(!camera1.GetParent());
+  view.SelectCamera("camera1");
+  DALI_TEST_CHECK(camera1.GetParent());
+  DALI_TEST_EQUALS(camera1, view.GetSelectedCamera(), TEST_LOCATION);
+
+  camera1.SetProperty(Dali::Actor::Property::POSITION, Vector3::ONE * -50.0f);
+  view.Add(camera1);
+
+  CameraActor camera2 = CameraActor::New3DCamera();
+  camera2.SetProperty(Dali::Actor::Property::NAME, "camera2");
+  view.AddCamera(camera2);
+  camera2.SetProperty(Dali::Actor::Property::POSITION, Vector3::ONE * 100.0f);
+
+  application.SendNotification();
+  application.Render();
+
+  bool                  signalReceived(false);
+  TransitionFinishCheck finishCheck(signalReceived);
+  view.CameraTransitionFinishedSignal().Connect(&application, finishCheck);
+
+  view.StartCameraTransition("camera2", 1.0f);
+
+  CameraActor camera3 = CameraActor::New3DCamera();
+  camera3.SetProperty(Dali::Actor::Property::NAME, "camera3");
+  view.AddCamera(camera3);
+  view.SelectCamera("camera3");
+
+  DALI_TEST_NOT_EQUALS(camera3, view.GetSelectedCamera(), 0.0f, TEST_LOCATION);
+  DALI_TEST_EQUALS(camera1, view.GetSelectedCamera(), TEST_LOCATION);
+
+  application.SendNotification();
+  application.Render(500);
+  application.SendNotification();
+
+  // We didn't expect the animation to finish yet
+  finishCheck.CheckSignalNotReceived();
+
+  CameraActor currentCamera = view.GetSelectedCamera();
+  DALI_TEST_CHECK(currentCamera);
+  DALI_TEST_NOT_EQUALS(currentCamera, camera1, 0.0f, TEST_LOCATION);
+  DALI_TEST_NOT_EQUALS(currentCamera, camera2, 0.0f, TEST_LOCATION);
+
+  view.SelectCamera(view.GetCameraCount() - 1);
+  DALI_TEST_NOT_EQUALS(camera3, view.GetSelectedCamera(), 0.0f, TEST_LOCATION);
+  DALI_TEST_EQUALS(currentCamera, view.GetSelectedCamera(), TEST_LOCATION);
+
+  application.SendNotification();
+  application.Render(600);
+  application.SendNotification();
+
+  finishCheck.CheckSignalReceived();
+
+  CameraActor finalCamera = view.GetSelectedCamera();
+  DALI_TEST_EQUALS(finalCamera, camera2, TEST_LOCATION);
+
+  view.SelectCamera("camera3");
+  DALI_TEST_EQUALS(camera3, view.GetSelectedCamera(), TEST_LOCATION);
+
+  END_TEST;
+}
+
+int UtcDaliSceneViewStartCameraTransitionDuringTransition(void)
+{
+  ToolkitTestApplication application;
+
+  Scene3D::SceneView view = Scene3D::SceneView::New();
+  application.GetScene().Add(view);
+
+  CameraActor camera1 = CameraActor::New3DCamera();
+  camera1.SetProperty(Dali::Actor::Property::NAME, "camera1");
+  view.AddCamera(camera1);
+  DALI_TEST_CHECK(!camera1.GetParent());
+  view.SelectCamera("camera1");
+  DALI_TEST_CHECK(camera1.GetParent());
+  DALI_TEST_EQUALS(camera1, view.GetSelectedCamera(), TEST_LOCATION);
+
+  camera1.SetProperty(Dali::Actor::Property::POSITION, Vector3::ONE * -50.0f);
+  view.Add(camera1);
+
+  CameraActor camera2 = CameraActor::New3DCamera();
+  camera2.SetProperty(Dali::Actor::Property::NAME, "camera2");
+  view.AddCamera(camera2);
+  camera2.SetProperty(Dali::Actor::Property::POSITION, Vector3::ONE * 100.0f);
+
+  application.SendNotification();
+  application.Render();
+
+  bool                  signalReceived(false);
+  TransitionFinishCheck finishCheck(signalReceived);
+  view.CameraTransitionFinishedSignal().Connect(&application, finishCheck);
+
+  view.StartCameraTransition("camera2", 1.0f);
+
+  application.SendNotification();
+  application.Render(500);
+  application.SendNotification();
+
+  // We didn't expect the animation to finish yet
+  finishCheck.CheckSignalNotReceived();
+
+  CameraActor camera3 = CameraActor::New3DCamera();
+  camera3.SetProperty(Dali::Actor::Property::NAME, "camera3");
+  view.AddCamera(camera3);
+
+  view.StartCameraTransition("camera3", 1.0f);
+
+  application.SendNotification();
+  application.Render(600);
+  application.SendNotification();
+
+  finishCheck.CheckSignalReceived();
+
+  CameraActor finalCamera = view.GetSelectedCamera();
+  DALI_TEST_EQUALS(finalCamera, camera2, TEST_LOCATION);
+
+  END_TEST;
+}
+
+int UtcDaliSceneViewCameraTransition1(void)
+{
+  ToolkitTestApplication application;
+
+  Scene3D::SceneView view = Scene3D::SceneView::New();
+  application.GetScene().Add(view);
+
+  CameraActor camera1 = CameraActor::New3DCamera();
+  camera1.SetProperty(Dali::Actor::Property::NAME, "camera1");
+  view.AddCamera(camera1);
+  DALI_TEST_CHECK(!camera1.GetParent());
+  view.SelectCamera("camera1");
+  DALI_TEST_CHECK(camera1.GetParent());
+  DALI_TEST_EQUALS(camera1, view.GetSelectedCamera(), TEST_LOCATION);
+
+  Scene3D::Model model1 = Scene3D::Model::New();
+  model1.SetProperty(Dali::Actor::Property::POSITION, Vector3::ONE * -50.0f);
+  view.Add(model1);
+
+  camera1.SetProperty(Dali::Actor::Property::POSITION, Vector3::ONE * -50.0f);
+  camera1.SetNearClippingPlane(10.0f);
+  camera1.SetFarClippingPlane(100.0f);
+  model1.Add(camera1);
+
+  CameraActor camera2 = CameraActor::New3DCamera();
+  camera2.SetProperty(Dali::Actor::Property::NAME, "camera2");
+  view.AddCamera(camera2);
+  camera2.SetProperty(Dali::Actor::Property::POSITION, Vector3::ONE * 100.0f);
+  camera2.SetNearClippingPlane(5.0f);
+  camera2.SetFarClippingPlane(50.0f);
+
+  Scene3D::Model model2 = Scene3D::Model::New();
+  model2.SetProperty(Dali::Actor::Property::POSITION, Vector3::ONE * 100.0f);
+  view.Add(model2);
+  model2.Add(camera2);
+
+  application.SendNotification();
+  application.Render();
+
+  camera1.SetProperty(Dali::DevelCameraActor::Property::PROJECTION_DIRECTION, Dali::DevelCameraActor::ProjectionDirection::VERTICAL);
+  camera2.SetProperty(Dali::DevelCameraActor::Property::PROJECTION_DIRECTION, Dali::DevelCameraActor::ProjectionDirection::HORIZONTAL);
+  camera1.SetFieldOfView(1.0f); // Vertical : 1.0f, Horizontal : 0.533293254f
+  camera2.SetFieldOfView(1.0f); // Vertical : 1.65924551f, Horizontal : 1.0f
+  camera1.SetAspectRatio(0.5f);
+  camera2.SetAspectRatio(0.5f);
+  tet_printf("camera1 fov : %f\n", camera1.GetFieldOfView());
+  tet_printf("camera2 fov : %f\n", camera2.GetFieldOfView());
+  tet_printf("camera1 aspect : %f\n", camera1.GetAspectRatio());
+  tet_printf("camera2 aspect : %f\n", camera2.GetAspectRatio());
+  tet_printf("camera1 direction : %d\n", camera1.GetProperty<Dali::DevelCameraActor::ProjectionDirection>(Dali::DevelCameraActor::Property::PROJECTION_DIRECTION));
+  tet_printf("camera2 direction : %d\n", camera2.GetProperty<Dali::DevelCameraActor::ProjectionDirection>(Dali::DevelCameraActor::Property::PROJECTION_DIRECTION));
+
+  bool                  signalReceived(false);
+  TransitionFinishCheck finishCheck(signalReceived);
+  view.CameraTransitionFinishedSignal().Connect(&application, finishCheck);
+
+  view.StartCameraTransition("camera2", 1.0f);
+
+  application.SendNotification();
+  application.Render(500);
+  application.SendNotification();
+
+  // We didn't expect the animation to finish yet
+  finishCheck.CheckSignalNotReceived();
+
+  CameraActor currentCamera = view.GetSelectedCamera();
+  DALI_TEST_CHECK(currentCamera);
+  DALI_TEST_NOT_EQUALS(currentCamera, camera1, 0.0f, TEST_LOCATION);
+  DALI_TEST_NOT_EQUALS(currentCamera, camera2, 0.0f, TEST_LOCATION);
+
+  Vector3 currentPosition = currentCamera.GetCurrentProperty<Vector3>(Dali::Actor::Property::POSITION);
+  DALI_TEST_EQUALS(currentPosition, Vector3::ONE * 50.0f, TEST_LOCATION);
+  DALI_TEST_EQUALS(currentCamera.GetNearClippingPlane(), 5.0f, TEST_LOCATION);
+  DALI_TEST_EQUALS(currentCamera.GetFarClippingPlane(), 100.0f, TEST_LOCATION);
+  float currentFov =  (0.533293254f + 1.0f) / 2.0f;
+  DALI_TEST_EQUALS(currentCamera.GetProperty<Dali::DevelCameraActor::ProjectionDirection>(Dali::DevelCameraActor::Property::PROJECTION_DIRECTION), Dali::DevelCameraActor::ProjectionDirection::HORIZONTAL, TEST_LOCATION);
+  DALI_TEST_EQUALS(currentCamera.GetCurrentProperty<float>(Dali::CameraActor::Property::FIELD_OF_VIEW), currentFov, 0.05f, TEST_LOCATION);
+
+  application.SendNotification();
+  application.Render(600);
+  application.SendNotification();
+
+  finishCheck.CheckSignalReceived();
+
+  CameraActor finalCamera = view.GetSelectedCamera();
+  DALI_TEST_EQUALS(finalCamera, camera2, TEST_LOCATION);
+
+  END_TEST;
+}
+
+int UtcDaliSceneViewCameraTransition2(void)
+{
+  ToolkitTestApplication application;
+
+  Scene3D::SceneView view = Scene3D::SceneView::New();
+  application.GetScene().Add(view);
+
+  CameraActor camera1 = CameraActor::New3DCamera();
+  camera1.SetProperty(Dali::Actor::Property::NAME, "camera1");
+  view.AddCamera(camera1);
+  DALI_TEST_CHECK(!camera1.GetParent());
+  view.SelectCamera("camera1");
+  DALI_TEST_CHECK(camera1.GetParent());
+  DALI_TEST_EQUALS(camera1, view.GetSelectedCamera(), TEST_LOCATION);
+
+  Scene3D::Model model1 = Scene3D::Model::New();
+  model1.SetProperty(Dali::Actor::Property::POSITION, Vector3::ONE * -50.0f);
+  view.Add(model1);
+
+  camera1.SetProperty(Dali::Actor::Property::POSITION, Vector3::ONE * -50.0f);
+  camera1.SetNearClippingPlane(10.0f);
+  camera1.SetFarClippingPlane(100.0f);
+  model1.Add(camera1);
+
+  CameraActor camera2 = CameraActor::New3DCamera();
+  camera2.SetProperty(Dali::Actor::Property::NAME, "camera2");
+  view.AddCamera(camera2);
+  camera2.SetProperty(Dali::Actor::Property::POSITION, Vector3::ONE * 200.0f);
+  camera2.SetNearClippingPlane(5.0f);
+  camera2.SetFarClippingPlane(50.0f);
+  // Camera2 is not added on SceneView, it will added on root layer automatically.
+
+  application.SendNotification();
+  application.Render();
+
+  bool                  signalReceived(false);
+  TransitionFinishCheck finishCheck(signalReceived);
+  view.CameraTransitionFinishedSignal().Connect(&application, finishCheck);
+
+  camera1.SetProjectionMode(Dali::Camera::ProjectionMode::ORTHOGRAPHIC_PROJECTION);
+  camera2.SetProjectionMode(Dali::Camera::ProjectionMode::ORTHOGRAPHIC_PROJECTION);
+  camera1.SetProperty(Dali::DevelCameraActor::Property::PROJECTION_DIRECTION, Dali::DevelCameraActor::ProjectionDirection::VERTICAL);
+  camera2.SetProperty(Dali::DevelCameraActor::Property::PROJECTION_DIRECTION, Dali::DevelCameraActor::ProjectionDirection::HORIZONTAL);
+
+  camera1.SetProperty(Dali::DevelCameraActor::Property::ORTHOGRAPHIC_SIZE, 10.0f);  // Vertical : 10.0f, Horizontal : 5.0f
+  camera2.SetProperty(Dali::DevelCameraActor::Property::ORTHOGRAPHIC_SIZE, 10.0f);  // Vertical : 20.0f, Horizontal : 10.0f
+  camera1.SetAspectRatio(0.5f);
+  camera2.SetAspectRatio(0.5f);
+
+  tet_printf("camera1 fov : %f\n", camera1.GetProperty<float>(Dali::DevelCameraActor::Property::ORTHOGRAPHIC_SIZE));
+  tet_printf("camera2 fov : %f\n", camera2.GetProperty<float>(Dali::DevelCameraActor::Property::ORTHOGRAPHIC_SIZE));
+  tet_printf("camera1 aspect : %f\n", camera1.GetAspectRatio());
+  tet_printf("camera2 aspect : %f\n", camera2.GetAspectRatio());
+  tet_printf("camera1 direction : %f\n", camera1.GetProperty<Dali::DevelCameraActor::ProjectionDirection>(Dali::DevelCameraActor::Property::PROJECTION_DIRECTION));
+  tet_printf("camera2 direction : %f\n", camera2.GetProperty<Dali::DevelCameraActor::ProjectionDirection>(Dali::DevelCameraActor::Property::PROJECTION_DIRECTION));
+
+  int camera2Index = view.GetCameraCount() - 1;
+  view.StartCameraTransition(camera2Index, 1.0f);
+
+  application.SendNotification();
+  application.Render(500);
+  application.SendNotification();
+
+  // We didn't expect the animation to finish yet
+  finishCheck.CheckSignalNotReceived();
+
+  CameraActor currentCamera = view.GetSelectedCamera();
+  DALI_TEST_CHECK(currentCamera);
+  DALI_TEST_NOT_EQUALS(currentCamera, camera1, 0.0f, TEST_LOCATION);
+  DALI_TEST_NOT_EQUALS(currentCamera, camera2, 0.0f, TEST_LOCATION);
+
+  Vector3 currentPosition = currentCamera.GetCurrentProperty<Vector3>(Dali::Actor::Property::POSITION);
+  DALI_TEST_EQUALS(currentPosition, Vector3::ONE * 50.0f, TEST_LOCATION);
+  DALI_TEST_EQUALS(currentCamera.GetNearClippingPlane(), 5.0f, TEST_LOCATION);
+  DALI_TEST_EQUALS(currentCamera.GetFarClippingPlane(), 100.0f, TEST_LOCATION);
+  float currentOrthographicSize = (5.0f + 10.0f) / 2.0f;
+  DALI_TEST_EQUALS(currentCamera.GetProperty<Dali::DevelCameraActor::ProjectionDirection>(Dali::DevelCameraActor::Property::PROJECTION_DIRECTION), Dali::DevelCameraActor::ProjectionDirection::HORIZONTAL, TEST_LOCATION);
+  DALI_TEST_EQUALS(currentCamera.GetCurrentProperty<float>(Dali::DevelCameraActor::Property::ORTHOGRAPHIC_SIZE), currentOrthographicSize, 0.05f, TEST_LOCATION);
+
+  application.SendNotification();
+  application.Render(600);
+  application.SendNotification();
+
+  finishCheck.CheckSignalReceived();
+
+  CameraActor finalCamera = view.GetSelectedCamera();
+  DALI_TEST_EQUALS(finalCamera, camera2, TEST_LOCATION);
+
   END_TEST;
 }
\ No newline at end of file
index 40c97684f9d636d22726fbb0b0519f50ad4c92a1..ff774d60fd80fafb717166c700770b3027caecaf 100644 (file)
@@ -25,6 +25,7 @@
 #include <dali-toolkit/internal/controls/control/control-data-impl.h>
 #include <dali-toolkit/public-api/image-loader/image-url.h>
 #include <dali-toolkit/public-api/image-loader/image.h>
+#include <dali/devel-api/actors/actor-devel.h>
 #include <dali/devel-api/actors/camera-actor-devel.h>
 #include <dali/devel-api/adaptor-framework/image-loading.h>
 #include <dali/devel-api/adaptor-framework/window-devel.h>
@@ -312,6 +313,16 @@ bool CheckInside(Actor root, Actor actor)
   return false;
 }
 
+void ConvertFovFromVerticalToHorizontal(float aspect, float& fov)
+{
+  fov = 2.0f * (float)std::atan(std::tan(fov * 0.5f) * aspect);
+}
+
+void ConvertFovFromHorizontalToVertical(float aspect, float& fov)
+{
+  fov = 2.0f * (float)std::atan(std::tan(fov * 0.5f) / aspect);
+}
+
 } // anonymous namespace
 
 SceneView::SceneView()
@@ -346,6 +357,12 @@ SceneView::~SceneView()
     }
     mSelectedCamera.OffSceneSignal().Disconnect(this, &SceneView::OnCameraDisconnected);
 
+    if(mInCameraTransition)
+    {
+      mTransitionAnimation.Stop();
+      ResetTransition();
+    }
+
     // Request image resource GC
     Dali::Scene3D::Internal::ImageResourceLoader::RequestGarbageCollect();
   }
@@ -439,14 +456,34 @@ CameraActor SceneView::GetCamera(const std::string& name) const
 
 void SceneView::SelectCamera(uint32_t index)
 {
+  if(mInCameraTransition)
+  {
+    DALI_LOG_ERROR("Cannot change camera during Camera Transition.\n");
+    return;
+  }
   UpdateCamera(GetCamera(index));
 }
 
 void SceneView::SelectCamera(const std::string& name)
 {
+  if(mInCameraTransition)
+  {
+    DALI_LOG_ERROR("Cannot change camera during Camera Transition.\n");
+    return;
+  }
   UpdateCamera(GetCamera(name));
 }
 
+void SceneView::StartCameraTransition(uint32_t index, float durationSeconds, Dali::AlphaFunction alphaFunction)
+{
+  RegisterCameraTransition(GetCamera(index), durationSeconds, alphaFunction);
+}
+
+void SceneView::StartCameraTransition(std::string name, float durationSeconds, Dali::AlphaFunction alphaFunction)
+{
+  RegisterCameraTransition(GetCamera(name), durationSeconds, alphaFunction);
+}
+
 void SceneView::RegisterSceneItem(Scene3D::Internal::LightObserver* item)
 {
   if(item)
@@ -957,6 +994,11 @@ Dali::Scene3D::SceneView::CaptureFinishedSignalType& SceneView::CaptureFinishedS
   return mCaptureFinishedSignal;
 }
 
+Dali::Scene3D::SceneView::CameraTransitionFinishedSignalType& SceneView::CameraTransitionFinishedSignal()
+{
+  return mCameraTransitionFinishedSignal;
+}
+
 Dali::Scene3D::Loader::ShaderManagerPtr SceneView::GetShaderManager() const
 {
   return mShaderManager;
@@ -1196,6 +1238,12 @@ void SceneView::OnSceneDisconnection()
   mFrameBuffer.Reset();
   mShadowFrameBuffer.Reset();
 
+  if(mInCameraTransition)
+  {
+    mTransitionAnimation.Stop();
+    ResetTransition();
+  }
+
   Control::OnSceneDisconnection();
 }
 
@@ -1660,14 +1708,181 @@ bool SceneView::OnTimeOut()
 
 void SceneView::OnCameraDisconnected(Dali::Actor actor)
 {
-  CameraActor selectedCamera = GetSelectedCamera();
-  if(selectedCamera == actor)
+  if(!mIsProcessorRegistered)
+  {
+    mIsProcessorRegistered = true;
+    Adaptor::Get().RegisterProcessorOnce(*this);
+  }
+}
+
+void SceneView::RegisterCameraTransition(CameraActor destinationCamera, float durationSeconds, Dali::AlphaFunction alphaFunction)
+{
+  if(mInCameraTransition)
+  {
+    DALI_LOG_ERROR("Cannot start Camera transition before previous Camera transition is finished.\n");
+    return;
+  }
+
+  mTransitionSourceCamera      = GetSelectedCamera();
+  mTransitionDestinationCamera = destinationCamera;
+  mTransitionDurationSeconds   = durationSeconds;
+  mTransitionAlphaFunction     = alphaFunction;
+  mInCameraTransition          = true;
+
+  if(!mIsProcessorRegistered)
+  {
+    mIsProcessorRegistered = true;
+    Adaptor::Get().RegisterProcessorOnce(*this);
+  }
+}
+
+void SceneView::RequestCameraTransition()
+{
+  if(mTransitionSourceCamera && mTransitionDestinationCamera && !(mTransitionSourceCamera == mTransitionDestinationCamera))
   {
-    if(!selectedCamera || !CheckInside(mRootLayer, selectedCamera))
+    Vector3 sourceWorldPosition = mTransitionSourceCamera.GetProperty<Vector3>(Dali::Actor::Property::WORLD_POSITION);
+    Quaternion sourceWorldOrientation = mTransitionSourceCamera.GetProperty<Quaternion>(Dali::Actor::Property::WORLD_ORIENTATION);
+
+    if(!CheckInside(mRootLayer, mTransitionDestinationCamera))
+    {
+      mRootLayer.Add(mTransitionDestinationCamera);
+    }
+
+    Vector3 destinationWorldPosition;
+    Quaternion destinationWorldOrientation;
+    Vector3 destinationWorldScale;
+    Dali::Matrix destinationWorldTransform = Dali::DevelActor::GetWorldTransform(mTransitionDestinationCamera);
+    destinationWorldTransform.GetTransformComponents(destinationWorldPosition, destinationWorldOrientation, destinationWorldScale);
+
+    if(!mTransitionAnimation)
+    {
+      mTransitionAnimation = Dali::Animation::New(mTransitionDurationSeconds);
+    }
+
+    if(mTransitionAnimation.GetState() != Animation::State::STOPPED)
+    {
+      mTransitionAnimation.Stop();
+    }
+    mTransitionAnimation.Clear();
+
+    Dali::KeyFrames positionKeyFrames = Dali::KeyFrames::New();
+    positionKeyFrames.Add(0.0f, sourceWorldPosition);
+    positionKeyFrames.Add(1.0f, destinationWorldPosition);
+
+    Dali::KeyFrames orientationKeyFrames = Dali::KeyFrames::New();
+    orientationKeyFrames.Add(0.0f, sourceWorldOrientation);
+    orientationKeyFrames.Add(1.0f, destinationWorldOrientation);
+
+    mTransitionCamera = Dali::CameraActor::New3DCamera();
+    mTransitionCamera.SetProperty(Dali::Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
+    mTransitionCamera.SetProperty(Dali::Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
+    mRootLayer.Add(mTransitionCamera);
+
+    mTransitionAnimation.AnimateBetween(Dali::Property(mTransitionCamera, Dali::Actor::Property::POSITION), positionKeyFrames, mTransitionAlphaFunction, Dali::Animation::Interpolation::LINEAR);
+    mTransitionAnimation.AnimateBetween(Dali::Property(mTransitionCamera, Dali::Actor::Property::ORIENTATION), orientationKeyFrames, mTransitionAlphaFunction, Dali::Animation::Interpolation::LINEAR);
+
+    Dali::DevelCameraActor::ProjectionDirection sourceProjectionDirection      = mTransitionSourceCamera.GetProperty<Dali::DevelCameraActor::ProjectionDirection>(Dali::DevelCameraActor::Property::PROJECTION_DIRECTION);
+    Dali::DevelCameraActor::ProjectionDirection destinationProjectionDirection = mTransitionDestinationCamera.GetProperty<Dali::DevelCameraActor::ProjectionDirection>(Dali::DevelCameraActor::Property::PROJECTION_DIRECTION);
+    if(mTransitionDestinationCamera.GetProjectionMode() == Dali::Camera::ProjectionMode::PERSPECTIVE_PROJECTION)
+    {
+      float sourceFieldOfView = mTransitionSourceCamera.GetFieldOfView();
+      float destinationFieldOfView = mTransitionDestinationCamera.GetFieldOfView();
+
+      if(sourceProjectionDirection != destinationProjectionDirection)
+      {
+        float aspect = mTransitionDestinationCamera.GetAspectRatio();
+        if(destinationProjectionDirection == Dali::DevelCameraActor::ProjectionDirection::VERTICAL)
+        {
+          ConvertFovFromHorizontalToVertical(aspect, sourceFieldOfView);
+        }
+        else
+        {
+          ConvertFovFromVerticalToHorizontal(aspect, sourceFieldOfView);
+        }
+      }
+
+      KeyFrames fieldOfViewKeyFrames = KeyFrames::New();
+      fieldOfViewKeyFrames.Add(0.0f, sourceFieldOfView);
+      fieldOfViewKeyFrames.Add(1.0f, destinationFieldOfView);
+      mTransitionAnimation.AnimateBetween(Dali::Property(mTransitionCamera, Dali::CameraActor::Property::FIELD_OF_VIEW), fieldOfViewKeyFrames, mTransitionAlphaFunction, Dali::Animation::Interpolation::LINEAR);
+    }
+    else
     {
-      UpdateCamera(mDefaultCamera);
+      float sourceOrthographicSize = mTransitionSourceCamera.GetProperty<float>(Dali::DevelCameraActor::Property::ORTHOGRAPHIC_SIZE);
+      float destinationOrthographicSize = mTransitionDestinationCamera.GetProperty<float>(Dali::DevelCameraActor::Property::ORTHOGRAPHIC_SIZE);
+
+      if(sourceProjectionDirection != destinationProjectionDirection)
+      {
+        float aspect = mTransitionDestinationCamera.GetAspectRatio();
+        if(destinationProjectionDirection == Dali::DevelCameraActor::ProjectionDirection::VERTICAL)
+        {
+          sourceOrthographicSize = sourceOrthographicSize / aspect;
+        }
+        else
+        {
+          sourceOrthographicSize = sourceOrthographicSize * aspect;
+        }
+      }
+
+      KeyFrames orthographicSizeKeyFrames = KeyFrames::New();
+      orthographicSizeKeyFrames.Add(0.0f, sourceOrthographicSize);
+      orthographicSizeKeyFrames.Add(1.0f, destinationOrthographicSize);
+      mTransitionAnimation.AnimateBetween(Dali::Property(mTransitionCamera, Dali::DevelCameraActor::Property::ORTHOGRAPHIC_SIZE), orthographicSizeKeyFrames, mTransitionAlphaFunction, Dali::Animation::Interpolation::LINEAR);
     }
+
+    float destinationNearPlaneDistance = mTransitionDestinationCamera.GetNearClippingPlane();
+    float destinationFarPlaneDistance = mTransitionDestinationCamera.GetFarClippingPlane();
+    mTransitionCamera.SetNearClippingPlane(std::min(mTransitionSourceCamera.GetNearClippingPlane(), destinationNearPlaneDistance));
+    mTransitionCamera.SetFarClippingPlane(std::max(mTransitionSourceCamera.GetFarClippingPlane(), destinationFarPlaneDistance));
+
+    mTransitionCamera.SetProperty(Dali::DevelCameraActor::Property::PROJECTION_DIRECTION, destinationProjectionDirection);
+    mTransitionCamera.SetProjectionMode(mTransitionDestinationCamera.GetProjectionMode());
+
+    UpdateCamera(mTransitionCamera);
+
+    mTransitionAnimation.FinishedSignal().Connect(this, &SceneView::OnTransitionFinished);
+
+    mTransitionAnimation.Play();
+  }
+  else
+  {
+    ResetTransition();
+  }
+}
+
+void SceneView::ResetTransition()
+{
+  mTransitionCamera.Reset();
+  mTransitionSourceCamera.Reset();
+  mTransitionDestinationCamera.Reset();
+  mTransitionAnimation.Reset();
+  mInCameraTransition = false;
+}
+
+void SceneView::OnTransitionFinished(Animation& animation)
+{
+  UpdateCamera(mTransitionDestinationCamera);
+  ResetTransition();
+
+  auto                     self = Self();
+  Dali::Scene3D::SceneView handle(Dali::Scene3D::SceneView::DownCast(self));
+  mCameraTransitionFinishedSignal.Emit(handle);
+}
+
+void SceneView::Process(bool postProcessor)
+{
+  CameraActor selectedCamera = GetSelectedCamera();
+  if(!selectedCamera || !CheckInside(mRootLayer, selectedCamera))
+  {
+    UpdateCamera(mDefaultCamera);
+  }
+
+  if(mInCameraTransition && !mTransitionCamera)
+  {
+    RequestCameraTransition();
   }
+
+  mIsProcessorRegistered = false;
 }
 
 } // namespace Internal
index c346d3b8e693d4fa791abf4975bfb8916eee5da5..ccc98e9a17773b4f47f84b68a18d6f98bec18329 100644 (file)
@@ -52,7 +52,7 @@ namespace Internal
 /**
  * @brief Impl class for SceneView.
  */
-class SceneView : public Dali::Toolkit::Internal::Control
+class SceneView : public Dali::Toolkit::Internal::Control, public Integration::Processor
 {
 public:
   /**
@@ -102,6 +102,16 @@ public:
    */
   void SelectCamera(const std::string& name);
 
+  /**
+   * @copydoc SceneView::StartCameraTransition()
+   */
+  void StartCameraTransition(uint32_t index, float durationSeconds, Dali::AlphaFunction alphaFunction);
+
+  /**
+   * @copydoc SceneView::StartCameraTransition()
+   */
+  void StartCameraTransition(std::string name, float durationSeconds, Dali::AlphaFunction alphaFunction);
+
   /**
    * @brief Register an item.
    *
@@ -250,10 +260,15 @@ public:
   int32_t Capture(Dali::CameraActor camera, const Vector2& size);
 
   /**
-   * @copydoc SceneView::FinishedSignal
+   * @copydoc SceneView::CaptureFinishedSignal
    */
   Dali::Scene3D::SceneView::CaptureFinishedSignalType& CaptureFinishedSignal();
 
+  /**
+   * @copydoc SceneView::CameraTransitionFinishedSignal
+   */
+  Dali::Scene3D::SceneView::CameraTransitionFinishedSignalType& CameraTransitionFinishedSignal();
+
   /**
    * @brief Retrieves ShaderManager of this SceneView.
    * @return ShaderManager of this SceneView.
@@ -461,6 +476,47 @@ private:
    */
   void OnCameraDisconnected(Dali::Actor actor);
 
+  /**
+   * @brief Registers Camera Transition to processor
+   */
+  void RegisterCameraTransition(CameraActor destinationCamera, float durationSeconds, Dali::AlphaFunction alphaFunction);
+
+  /**
+   * @brief Requests Camera Transition
+   * @note This method is called in Process.
+   */
+  void RequestCameraTransition();
+
+  /**
+   * @brief Resets Transition information.
+   * This method is called when the transition is finished or invalid transition is requested.
+   */
+  void ResetTransition();
+
+  /**
+   * @brief Camera Transition finished callback.
+   * @param[in] animation animation for this Transition
+   */
+  void OnTransitionFinished(Animation& animation);
+
+private: // Implementation of Processor
+
+  /**
+   * @copydoc Dali::Integration::Processor::Process()
+   * @note This process check the SceneView has activated Camera or not.
+   * If not, select default camera.
+   * And, this process generates Camera transition animation that is triggered by StartCameraTransition method.
+   */
+  void Process(bool postProcessor) override;
+
+  /**
+   * @copydoc Dali::Integration::Processor::GetProcessorName()
+   */
+  std::string_view GetProcessorName() const override
+  {
+    return "SceneViewImpl";
+  }
+
 private:
   /**
    * Data to store Capture related objects.
@@ -500,6 +556,16 @@ private:
   uint8_t                                             mFrameBufferMultiSamplingLevel{0u};
   Dali::Scene3D::SceneView::CaptureFinishedSignalType mCaptureFinishedSignal;
 
+  // camera Transition
+  CameraActor                                                  mTransitionCamera;
+  CameraActor                                                  mTransitionSourceCamera;
+  CameraActor                                                  mTransitionDestinationCamera;
+  float                                                        mTransitionDurationSeconds;
+  AlphaFunction                                                mTransitionAlphaFunction;
+  bool                                                         mInCameraTransition{false};
+  Animation                                                    mTransitionAnimation;
+  Dali::Scene3D::SceneView::CameraTransitionFinishedSignalType mCameraTransitionFinishedSignal;
+
   int32_t                                                                mCaptureId{0};     // Capture ID for requested capture, this is incrementally increasing.
   std::vector<std::pair<Dali::RenderTask, std::shared_ptr<CaptureData>>> mCaptureContainer; // Container that stores CaptureData until the Capture is finished.
   Dali::Timer                                                            mCaptureTimer;     // Timer to check the capture is time out or not.
@@ -548,6 +614,7 @@ private:
   bool                        mSkyboxDirty{false};
   bool                        mIblDiffuseDirty{false};
   bool                        mIblSpecularDirty{false};
+  bool                        mIsProcessorRegistered{false};
 };
 
 } // namespace Internal
index aa4172bfd9f9deff6a756062882dab9ee7b9add3..754cf10ff388120641a6a14fae629115ec43da93 100644 (file)
@@ -102,6 +102,16 @@ void SceneView::SelectCamera(const std::string& name)
   GetImpl(*this).SelectCamera(name);
 }
 
+void SceneView::StartCameraTransition(uint32_t index, float durationSeconds, Dali::AlphaFunction alphaFunction)
+{
+  GetImpl(*this).StartCameraTransition(index, durationSeconds, alphaFunction);
+}
+
+void SceneView::StartCameraTransition(std::string name, float durationSeconds, Dali::AlphaFunction alphaFunction)
+{
+  GetImpl(*this).StartCameraTransition(name, durationSeconds, alphaFunction);
+}
+
 void SceneView::SetImageBasedLightSource(const std::string& diffuseUrl, const std::string& specularUrl, float scaleFactor)
 {
   GetImpl(*this).SetImageBasedLightSource(diffuseUrl, specularUrl, scaleFactor);
@@ -202,6 +212,11 @@ SceneView::CaptureFinishedSignalType& SceneView::CaptureFinishedSignal()
   return GetImpl(*this).CaptureFinishedSignal();
 }
 
+SceneView::CameraTransitionFinishedSignalType& SceneView::CameraTransitionFinishedSignal()
+{
+  return GetImpl(*this).CameraTransitionFinishedSignal();
+}
+
 } // namespace Scene3D
 
 } // namespace Dali
index 1b4314392c8fda16c7708c3ce52c381a3f68147a..88a21a0ef7d7a39267107a37b484755a11f7e0e8 100644 (file)
@@ -22,6 +22,7 @@
 #include <dali-toolkit/public-api/controls/control.h>
 #include <dali-toolkit/public-api/image-loader/image-url.h>
 #include <dali/public-api/actors/camera-actor.h>
+#include <dali/public-api/animation/animation.h>
 #include <dali/public-api/common/dali-common.h>
 
 // INTERNAL INCLUDES
@@ -176,6 +177,13 @@ public:
    */
   typedef Signal<void(SceneView, CaptureResult&)> CaptureFinishedSignalType;
 
+  /**
+   * @brief Typedef for camera transition finished signals sent by this class.
+   *
+   * @SINCE_2_3.37
+   */
+  typedef Signal<void(SceneView)> CameraTransitionFinishedSignalType;
+
   /**
    * @brief Create an initialized SceneView.
    *
@@ -334,6 +342,34 @@ public:
    */
   void SelectCamera(const std::string& name);
 
+  /**
+   * @brief Starts camera transition from currently selected camera to a camera of index.
+   * Camera Position, Orientation and FieldOfView(Orthogrpahic Size) are smoothly animated.
+   *
+   * @SINCE_2_3.37
+   * @param[in] index Index of destination Camera of Camera transition.
+   * @param[in] durationSeconds The duration in seconds.
+   * @param[in] alphaFunction The alpha function to apply.
+   * @note The selected camera is switched to the Camera of the index when the transition is finished.
+   * During camera transition, Selected Camera should not be changed by using SelectCamera() or StartCameraTransition() method.
+   * During camera transition, Camera properties of Selected Camera should not be changed.
+   */
+  void StartCameraTransition(uint32_t index, float durationSeconds, Dali::AlphaFunction alphaFunction = AlphaFunction::DEFAULT);
+
+  /**
+   * @brief Starts camera transition from currently selected camera to a camera of index.
+   * Camera Position, Orientation and FieldOfView(Orthogrpahic Size) are smoothly animated.
+   *
+   * @SINCE_2_3.37
+   * @param[in] name string keyword of destination Camera of Camera transition.
+   * @param[in] durationSeconds The duration in seconds.
+   * @param[in] alphaFunction The alpha function to apply.
+   * @note The selected camera is switched to the Camera of the input name when the transition is finished.
+   * During camera transition, Selected Camera should not be changed by using SelectCamera() or StartCameraTransition() method.
+   * During camera transition, Camera properties of Selected Camera should not be changed.
+   */
+  void StartCameraTransition(std::string name, float durationSeconds, Dali::AlphaFunction alphaFunction = AlphaFunction::DEFAULT);
+
   /**
    * @brief Sets Image Based Light Source to apply it on the all Models those added on this SceneView.
    *
@@ -533,6 +569,14 @@ public:
    */
   CaptureFinishedSignalType& CaptureFinishedSignal();
 
+  /**
+   * @brief Get camera transition finished signal.
+   *
+   * @SINCE_2_3.37
+   * @return camera transition finished signal instance.
+   */
+  CameraTransitionFinishedSignalType& CameraTransitionFinishedSignal();
+
 public: // Not intended for application developers
   /// @cond internal
   /**