[Tizen] Fix SceneView Capture Signal 00/318400/4
authorSeungho Baek <sbsh.baek@samsung.com>
Thu, 16 Jan 2025 08:49:16 +0000 (17:49 +0900)
committerSeungho Baek <sbsh.baek@samsung.com>
Tue, 21 Jan 2025 05:32:57 +0000 (14:32 +0900)
 - SceneView Capture Finished Signal uses CaptureResult struct as a return parameter.
 - It is not easy to use.
 - Remove State and check success or fail by using nullcheck of ImageUrl
 - Make SceneView::Capture always emit CaptureFinished event

Change-Id: I7b99d74e95aaceb6d00ec1eda697b8148851049a
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.h

index e909f9b92007aa5e4163e75d6c7f58a999a19cc1..37b1f98879d15bbae502d71c0423c83df1428ad6 100644 (file)
  */
 
 #include <dali-toolkit-test-suite-utils.h>
-#include <toolkit-event-thread-callback.h>
-#include <toolkit-timer.h>
-
 #include <dali-toolkit/dali-toolkit.h>
 #include <stdlib.h>
 #include <iostream>
 
 #include <dali-scene3d/public-api/controls/model/model.h>
 #include <dali-scene3d/public-api/controls/scene-view/scene-view.h>
-
+#include <toolkit-event-thread-callback.h>
 
 using namespace Dali;
 using namespace Dali::Toolkit;
@@ -1198,296 +1195,3 @@ int UtcDaliSceneViewMasking(void)
 
   END_TEST;
 }
-
-namespace
-{
-static bool                                   gCaptureFinishedCalled{false};
-static int32_t                                gCaptureId{-1};
-static Toolkit::ImageUrl                      gCapturedImageUrl;
-static Scene3D::SceneView::CaptureFinishState gCaptureFinishState{Scene3D::SceneView::CaptureFinishState::FAILED};
-
-void OnCaptureFinished(Scene3D::SceneView sceneView, Scene3D::SceneView::CaptureResult& captureResult)
-{
-  gCaptureFinishedCalled = true;
-  gCaptureId             = captureResult.captureId;
-  gCapturedImageUrl      = captureResult.imageUrl;
-  gCaptureFinishState    = captureResult.state;
-}
-
-static int32_t                                             gCapturedCount{0};
-static std::vector<int32_t>                                gCaptureIds;
-static std::vector<Toolkit::ImageUrl>                      gCapturedImageUrls;
-static std::vector<Scene3D::SceneView::CaptureFinishState> gCaptureFinishStates;
-
-void OnCaptureMultipleFinished(Scene3D::SceneView sceneView, Scene3D::SceneView::CaptureResult& captureResult)
-{
-  gCapturedCount++;
-  gCaptureIds.push_back(captureResult.captureId);
-  gCapturedImageUrls.push_back(captureResult.imageUrl);
-  gCaptureFinishStates.push_back(captureResult.state);
-}
-} // namespace
-
-int UtcDaliSceneViewCapture01(void)
-{
-  ToolkitTestApplication application;
-
-  Scene3D::SceneView view = Scene3D::SceneView::New();
-  view.CaptureFinishedSignal().Connect(OnCaptureFinished);
-  view.SetProperty(Dali::Actor::Property::SIZE, Vector2(100, 100));
-
-  application.GetScene().Add(view);
-
-  application.SendNotification();
-  application.Render();
-
-  Scene3D::Model modelView1 = Scene3D::Model::New(TEST_GLTF_FILE_NAME);
-  view.Add(modelView1);
-
-  application.SendNotification();
-  application.Render();
-  DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION);
-  application.SendNotification();
-  application.Render();
-
-  CameraActor camera = Dali::CameraActor::New();
-  camera.SetProperty(Dali::Actor::Property::NAME, "camera");
-  camera.SetProperty(Dali::Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
-  camera.SetProperty(Dali::Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
-  camera.SetFieldOfView(0.5f);
-  camera.SetNearClippingPlane(1.0f);
-  camera.SetFarClippingPlane(5000.0f);
-  camera.SetProperty(Dali::Actor::Property::POSITION, Vector3(20, 30, 40));
-
-  view.Add(camera);
-
-  gCaptureFinishedCalled = false;
-  gCaptureId = -1;
-  gCapturedImageUrl.Reset();
-  gCaptureFinishState = Scene3D::SceneView::CaptureFinishState::FAILED;
-  int32_t captureId = view.Capture(camera, Vector2(300, 300));
-
-  application.SendNotification();
-  application.Render();
-  application.SendNotification();
-  application.Render();
-  application.SendNotification();
-
-  DALI_TEST_EQUALS(gCaptureFinishedCalled, true, TEST_LOCATION);
-  DALI_TEST_EQUALS(gCaptureId, captureId, TEST_LOCATION);
-  DALI_TEST_EQUALS(gCapturedImageUrl.GetUrl().empty(), false, TEST_LOCATION);
-  DALI_TEST_EQUALS(gCaptureFinishState, Scene3D::SceneView::CaptureFinishState::SUCCEEDED, TEST_LOCATION);
-
-  Toolkit::ImageUrl tempImageUrl = gCapturedImageUrl;
-
-  gCaptureFinishedCalled = false;
-  gCaptureId = -1;
-  gCapturedImageUrl.Reset();
-  gCaptureFinishState = Scene3D::SceneView::CaptureFinishState::FAILED;
-  int32_t captureId2 = view.Capture(camera, Vector2(400, 400));
-
-  application.SendNotification();
-  application.Render();
-  application.SendNotification();
-  application.Render();
-  application.SendNotification();
-
-  DALI_TEST_EQUALS(gCaptureFinishedCalled, true, TEST_LOCATION);
-  DALI_TEST_NOT_EQUALS(captureId, captureId2, 0.1f, TEST_LOCATION);
-  DALI_TEST_EQUALS(gCaptureId, captureId2, TEST_LOCATION);
-  DALI_TEST_EQUALS(gCapturedImageUrl.GetUrl().empty(), false, TEST_LOCATION);
-  DALI_TEST_NOT_EQUALS(gCapturedImageUrl, tempImageUrl, 0.1f, TEST_LOCATION);
-  DALI_TEST_EQUALS(gCaptureFinishState, Scene3D::SceneView::CaptureFinishState::SUCCEEDED, TEST_LOCATION);
-
-  END_TEST;
-}
-
-int UtcDaliSceneViewCaptureCancel(void)
-{
-  ToolkitTestApplication application;
-
-  Scene3D::SceneView view = Scene3D::SceneView::New();
-  view.CaptureFinishedSignal().Connect(OnCaptureFinished);
-  view.SetProperty(Dali::Actor::Property::SIZE, Vector2(100, 100));
-
-  application.GetScene().Add(view);
-
-  application.SendNotification();
-  application.Render();
-
-  Scene3D::Model modelView1 = Scene3D::Model::New(TEST_GLTF_FILE_NAME);
-  view.Add(modelView1);
-
-  application.SendNotification();
-  application.Render();
-  DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION);
-  application.SendNotification();
-  application.Render();
-
-  CameraActor camera = Dali::CameraActor::New();
-  camera.SetProperty(Dali::Actor::Property::NAME, "camera");
-  camera.SetProperty(Dali::Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
-  camera.SetProperty(Dali::Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
-  camera.SetFieldOfView(0.5f);
-  camera.SetNearClippingPlane(1.0f);
-  camera.SetFarClippingPlane(5000.0f);
-  camera.SetProperty(Dali::Actor::Property::POSITION, Vector3(20, 30, 40));
-
-  view.Add(camera);
-
-  gCaptureFinishedCalled = false;
-  gCaptureId = -1;
-  gCapturedImageUrl.Reset();
-  gCaptureFinishState = Scene3D::SceneView::CaptureFinishState::FAILED;
-  int32_t captureId = view.Capture(camera, Vector2(300, 300));
-
-  view.Unparent();
-
-  DALI_TEST_EQUALS(gCaptureFinishedCalled, true, TEST_LOCATION);
-  DALI_TEST_EQUALS(gCaptureId, captureId, TEST_LOCATION);
-  DALI_TEST_EQUALS(!!gCapturedImageUrl, false, TEST_LOCATION);
-  DALI_TEST_EQUALS(gCaptureFinishState, Scene3D::SceneView::CaptureFinishState::FAILED, TEST_LOCATION);
-
-
-  gCaptureFinishedCalled = false;
-  gCaptureId = -1;
-  gCapturedImageUrl.Reset();
-  gCaptureFinishState = Scene3D::SceneView::CaptureFinishState::FAILED;
-
-  application.SendNotification();
-  application.Render();
-  application.SendNotification();
-  application.Render();
-  application.SendNotification();
-
-  DALI_TEST_EQUALS(gCaptureFinishedCalled, false, TEST_LOCATION);
-
-  END_TEST;
-}
-
-int UtcDaliSceneViewCaptureFailed(void)
-{
-  ToolkitTestApplication application;
-
-  Scene3D::SceneView view = Scene3D::SceneView::New();
-  view.CaptureFinishedSignal().Connect(OnCaptureFinished);
-  view.SetProperty(Dali::Actor::Property::SIZE, Vector2(100, 100));
-
-  application.GetScene().Add(view);
-
-  application.SendNotification();
-  application.Render();
-
-  Scene3D::Model modelView1 = Scene3D::Model::New(TEST_GLTF_FILE_NAME);
-  view.Add(modelView1);
-
-  application.SendNotification();
-  application.Render();
-  DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION);
-  application.SendNotification();
-  application.Render();
-
-  CameraActor camera = Dali::CameraActor::New();
-  camera.SetProperty(Dali::Actor::Property::NAME, "camera");
-  camera.SetProperty(Dali::Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
-  camera.SetProperty(Dali::Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
-  camera.SetFieldOfView(0.5f);
-  camera.SetNearClippingPlane(1.0f);
-  camera.SetFarClippingPlane(5000.0f);
-  camera.SetProperty(Dali::Actor::Property::POSITION, Vector3(20, 30, 40));
-
-  view.Add(camera);
-
-  gCaptureFinishedCalled = false;
-  gCaptureId = -1;
-  gCapturedImageUrl.Reset();
-  gCaptureFinishState = Scene3D::SceneView::CaptureFinishState::FAILED;
-  int32_t captureId = view.Capture(camera, Vector2(300, 300));
-
-  Test::EmitGlobalTimerSignal();
-  Test::EmitGlobalTimerSignal();
-  Test::EmitGlobalTimerSignal();
-
-  DALI_TEST_EQUALS(gCaptureFinishedCalled, true, TEST_LOCATION);
-  DALI_TEST_EQUALS(gCaptureId, captureId, TEST_LOCATION);
-  DALI_TEST_EQUALS(!!gCapturedImageUrl, false, TEST_LOCATION);
-  DALI_TEST_EQUALS(gCaptureFinishState, Scene3D::SceneView::CaptureFinishState::FAILED, TEST_LOCATION);
-
-  gCaptureFinishedCalled = false;
-  gCaptureId = -1;
-  gCapturedImageUrl.Reset();
-  gCaptureFinishState = Scene3D::SceneView::CaptureFinishState::FAILED;
-
-  application.SendNotification();
-  application.Render();
-  application.SendNotification();
-  application.Render();
-  application.SendNotification();
-
-  DALI_TEST_EQUALS(gCaptureFinishedCalled, false, TEST_LOCATION);
-
-  END_TEST;
-}
-
-int UtcDaliSceneViewCapture02(void)
-{
-  ToolkitTestApplication application;
-
-  Scene3D::SceneView view = Scene3D::SceneView::New();
-  view.CaptureFinishedSignal().Connect(OnCaptureMultipleFinished);
-  view.SetProperty(Dali::Actor::Property::SIZE, Vector2(100, 100));
-
-  application.GetScene().Add(view);
-
-  application.SendNotification();
-  application.Render();
-
-  Scene3D::Model modelView1 = Scene3D::Model::New(TEST_GLTF_FILE_NAME);
-  view.Add(modelView1);
-
-  application.SendNotification();
-  application.Render();
-  DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION);
-  application.SendNotification();
-  application.Render();
-
-  CameraActor camera = Dali::CameraActor::New();
-  camera.SetProperty(Dali::Actor::Property::NAME, "camera");
-  camera.SetProperty(Dali::Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
-  camera.SetProperty(Dali::Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
-  camera.SetFieldOfView(0.5f);
-  camera.SetNearClippingPlane(1.0f);
-  camera.SetFarClippingPlane(5000.0f);
-  camera.SetProperty(Dali::Actor::Property::POSITION, Vector3(20, 30, 40));
-
-  view.Add(camera);
-
-  gCapturedCount = 0;
-  gCaptureIds.clear();
-  gCapturedImageUrls.clear();
-  gCaptureFinishStates.clear();
-  int32_t captureId = view.Capture(camera, Vector2(300, 300));
-  int32_t captureId2 = view.Capture(camera, Vector2(300, 300));
-
-  application.SendNotification();
-  application.Render();
-  application.SendNotification();
-  application.Render();
-  application.SendNotification();
-
-  DALI_TEST_EQUALS(gCapturedCount, 2, TEST_LOCATION);
-  DALI_TEST_EQUALS(gCaptureIds.size(), 2, TEST_LOCATION);
-  auto idIter1 = std::find(gCaptureIds.begin(), gCaptureIds.end(), captureId);
-  bool isIter1 = idIter1 != gCaptureIds.end();
-  DALI_TEST_EQUALS(isIter1, true, TEST_LOCATION);
-  auto idIter2 = std::find(gCaptureIds.begin(), gCaptureIds.end(), captureId2);
-  bool isIter2 = idIter2 != gCaptureIds.end();
-  DALI_TEST_EQUALS(isIter2, true, TEST_LOCATION);
-
-  DALI_TEST_EQUALS(gCapturedImageUrls.size(), 2, TEST_LOCATION);
-  DALI_TEST_NOT_EQUALS(gCapturedImageUrls[0], gCapturedImageUrls[1], 0.1f, TEST_LOCATION);
-  DALI_TEST_EQUALS(gCaptureFinishStates[0], Scene3D::SceneView::CaptureFinishState::SUCCEEDED, TEST_LOCATION);
-  DALI_TEST_EQUALS(gCaptureFinishStates[1], Scene3D::SceneView::CaptureFinishState::SUCCEEDED, TEST_LOCATION);
-
-  END_TEST;
-}
\ No newline at end of file
index 3a5f54053aeb8835d65ee927374684115a9d3c14..450ab75986047829be3086a443e0fa2357f29e7e 100644 (file)
@@ -65,10 +65,10 @@ DALI_PROPERTY_REGISTRATION(Scene3D, SceneView, "CropToMask", BOOLEAN, CROP_TO_MA
 DALI_TYPE_REGISTRATION_END()
 
 Property::Index    RENDERING_BUFFER        = Dali::Toolkit::Control::CONTROL_PROPERTY_END_INDEX + 1;
-constexpr int32_t  DEFAULT_ORIENTATION     = 0;
-constexpr int32_t  INVALID_INDEX           = -1;
-constexpr int32_t  INVALID_CAPTURE_ID      = -1;
-constexpr uint32_t MAXIMUM_SIZE_SHADOW_MAP = 2048;
+static constexpr float    MIM_CAPTURE_SIZE        = 1.0f;
+static constexpr int32_t  DEFAULT_ORIENTATION     = 0;
+static constexpr int32_t  INVALID_INDEX           = -1;
+static constexpr uint32_t MAXIMUM_SIZE_SHADOW_MAP = 2048;
 
 static constexpr std::string_view SKYBOX_INTENSITY_STRING = "uIntensity";
 
@@ -300,6 +300,7 @@ SceneView::SceneView()
   mSkybox(),
   mSkyboxOrientation(Quaternion()),
   mSkyboxIntensity(1.0f),
+  mFailedCaptureCallbacks(nullptr),
   mShaderManager(new Scene3D::Loader::ShaderManager())
 {
 }
@@ -323,6 +324,19 @@ SceneView::~SceneView()
       Dali::AsyncTaskManager::Get().RemoveTask(mSkyboxLoadTask);
       mSkyboxLoadTask.Reset();
     }
+
+    for(auto&& capture : mCaptureContainer)
+    {
+      ResetCaptureData(capture.second);
+    }
+    mCaptureContainer.clear();
+    ResetCaptureTimer();
+
+    if(mFailedCaptureCallbacks && Adaptor::IsAvailable())
+    {
+      // Removes the callback from the callback manager in case the control is destroyed before the callback is executed.
+      Adaptor::Get().RemoveIdle(mFailedCaptureCallbacks);
+    }
   }
 }
 
@@ -820,92 +834,112 @@ Quaternion SceneView::GetSkyboxOrientation() const
 
 int32_t SceneView::Capture(Dali::CameraActor camera, const Vector2& size)
 {
-  if(size.x <= 0.0f || size.y <= 0.0f)
+  bool capturePossible = true;
+  if(size.x < MIM_CAPTURE_SIZE || size.y < MIM_CAPTURE_SIZE)
   {
     DALI_LOG_ERROR("The width and height should be positive.\n");
-    return INVALID_CAPTURE_ID;
+    capturePossible = false;
   }
 
   if(!mRenderTask)
   {
     DALI_LOG_ERROR("Capture Should be requested after the SceneView is on scene.");
-    return INVALID_CAPTURE_ID;
+    capturePossible = false;
   }
 
-  uint32_t width = unsigned(size.width);
-  uint32_t height = unsigned(size.height);
+  uint32_t width = std::max(1u, unsigned(size.width));
+  uint32_t height = std::max(1u, unsigned(size.height));
   if(width > Dali::GetMaxTextureSize() || height > Dali::GetMaxTextureSize())
   {
     DALI_LOG_ERROR("The input size is too large.\n");
-    return INVALID_CAPTURE_ID;
+    capturePossible = false;
   }
 
   if(!mRootLayer.GetProperty<bool>(Dali::Actor::Property::CONNECTED_TO_SCENE))
   {
     DALI_LOG_ERROR("Current SceneView is not connected on scene tree\n");
-    return INVALID_CAPTURE_ID;
+    capturePossible = false;
   }
 
-  if(!camera.GetProperty<bool>(Dali::Actor::Property::CONNECTED_TO_SCENE))
+  if(!capturePossible)
   {
-    mRootLayer.Add(camera);
+    mFailedCaptureRequests.push_back(mCaptureId);
+    if(!mFailedCaptureCallbacks && DALI_LIKELY(Adaptor::IsAvailable()))
+    {
+      mFailedCaptureCallbacks = MakeCallback(this, &SceneView::OnCaptureFailedIdle);
+      if(!Adaptor::Get().AddIdle(mFailedCaptureCallbacks, false))
+      {
+        mFailedCaptureCallbacks = nullptr;
+      }
+    }
   }
+  else
+  {
+    if(!camera.GetProperty<bool>(Dali::Actor::Property::CONNECTED_TO_SCENE))
+    {
+      mRootLayer.Add(camera);
+    }
 
-  std::shared_ptr<CaptureData> captureData = std::make_shared<CaptureData>();
-  captureData->mCaptureId                  = mCaptureId;
-  captureData->mCaptureTexture             = Dali::Texture::New(TextureType::TEXTURE_2D, Pixel::RGBA8888, width, height);
-  captureData->mCaptureFrameBuffer         = Dali::FrameBuffer::New(captureData->mCaptureTexture.GetWidth(), captureData->mCaptureTexture.GetHeight(), Dali::FrameBuffer::Attachment::DEPTH_STENCIL);
-  DevelFrameBuffer::SetMultiSamplingLevel(captureData->mCaptureFrameBuffer, mFrameBufferMultiSamplingLevel);
-  captureData->mCaptureFrameBuffer.AttachColorTexture(captureData->mCaptureTexture);
-
-  RenderTaskList taskList   = mSceneHolder.GetRenderTaskList();
-  captureData->mCaptureTask = taskList.CreateTask();
-  captureData->mCaptureTask.SetSourceActor(mRootLayer);
-  captureData->mCaptureTask.SetExclusive(true);
-  captureData->mCaptureTask.SetCullMode(false);
-  captureData->mCaptureTask.SetCameraActor(camera);
-  captureData->mCaptureTask.SetFrameBuffer(captureData->mCaptureFrameBuffer);
-  captureData->mCaptureTask.SetClearEnabled(true);
-  captureData->mCaptureTask.SetClearColor(Color::TRANSPARENT);
-  captureData->mCaptureTask.SetRefreshRate(Dali::RenderTask::REFRESH_ONCE);
-
-  captureData->mCaptureInvertCamera = Dali::CameraActor::New(size);
-  captureData->mCaptureInvertCamera.SetProperty(Dali::Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT);
-  captureData->mCaptureInvertCamera.SetProperty(Dali::Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
-  captureData->mCaptureInvertCamera.SetProperty(Dali::Actor::Property::POSITION_X, size.x / 2.0f);
-  captureData->mCaptureInvertCamera.SetProperty(Dali::Actor::Property::POSITION_Y, size.y / 2.0f);
-
-  captureData->mCaptureUrl       = Dali::Toolkit::Image::GenerateUrl(captureData->mCaptureFrameBuffer, 0u);
-  captureData->mCaptureImageView = Dali::Toolkit::ImageView::New(captureData->mCaptureUrl.GetUrl());
-  captureData->mCaptureImageView.SetProperty(Dali::Actor::Property::SIZE, size);
-  captureData->mCaptureImageView.Add(captureData->mCaptureInvertCamera);
-
-  mSceneHolder.Add(captureData->mCaptureImageView);
-
-  captureData->mCaptureInvertTexture     = Dali::Texture::New(TextureType::TEXTURE_2D, Pixel::RGBA8888, width, height);
-  captureData->mCaptureInvertFrameBuffer = Dali::FrameBuffer::New(captureData->mCaptureInvertTexture.GetWidth(), captureData->mCaptureInvertTexture.GetHeight(), Dali::FrameBuffer::Attachment::DEPTH_STENCIL);
-  captureData->mCaptureInvertFrameBuffer.AttachColorTexture(captureData->mCaptureInvertTexture);
-
-  captureData->mCaptureInvertTask = taskList.CreateTask();
-  captureData->mCaptureInvertTask.SetSourceActor(captureData->mCaptureImageView);
-  captureData->mCaptureInvertTask.SetExclusive(true);
-  captureData->mCaptureInvertTask.SetCullMode(false);
-  captureData->mCaptureInvertTask.SetCameraActor(captureData->mCaptureInvertCamera);
-  captureData->mCaptureInvertTask.SetFrameBuffer(captureData->mCaptureInvertFrameBuffer);
-  captureData->mCaptureInvertTask.SetClearEnabled(true);
-  captureData->mCaptureInvertTask.SetClearColor(Color::TRANSPARENT);
-  captureData->mCaptureInvertTask.SetRefreshRate(Dali::RenderTask::REFRESH_ONCE);
-  captureData->mCaptureInvertTask.FinishedSignal().Connect(this, &SceneView::OnCaptureFinished);
-
-  captureData->mStartTick = mTimerTickCount;
-
-  mCaptureContainer.push_back(std::make_pair(captureData->mCaptureInvertTask, captureData));
-
-  if(!mCaptureTimer)
-  {
-    mCaptureTimer = Dali::Timer::New(1000);
-    mCaptureTimer.TickSignal().Connect(this, &SceneView::OnTimeOut);
-    mCaptureTimer.Start();
+    std::shared_ptr<CaptureData> captureData = std::make_shared<CaptureData>();
+    captureData->mCaptureId                  = mCaptureId;
+    captureData->mCaptureTexture             = Dali::Texture::New(TextureType::TEXTURE_2D, Pixel::RGBA8888, width, height);
+    captureData->mCaptureFrameBuffer         = Dali::FrameBuffer::New(captureData->mCaptureTexture.GetWidth(), captureData->mCaptureTexture.GetHeight(), Dali::FrameBuffer::Attachment::DEPTH_STENCIL);
+    DevelFrameBuffer::SetMultiSamplingLevel(captureData->mCaptureFrameBuffer, mFrameBufferMultiSamplingLevel);
+    captureData->mCaptureFrameBuffer.AttachColorTexture(captureData->mCaptureTexture);
+
+    captureData->mCaptureCamera                    = camera;
+    captureData->mCaptureCameraOriginalAspectRatio = captureData->mCaptureCamera.GetAspectRatio();
+    captureData->mCaptureCamera.SetAspectRatio((float)width / (float)height);
+
+    RenderTaskList taskList   = mSceneHolder.GetRenderTaskList();
+    captureData->mCaptureTask = taskList.CreateTask();
+    captureData->mCaptureTask.SetSourceActor(mRootLayer);
+    captureData->mCaptureTask.SetExclusive(true);
+    captureData->mCaptureTask.SetCullMode(false);
+    captureData->mCaptureTask.SetCameraActor(captureData->mCaptureCamera);
+    captureData->mCaptureTask.SetFrameBuffer(captureData->mCaptureFrameBuffer);
+    captureData->mCaptureTask.SetClearEnabled(true);
+    captureData->mCaptureTask.SetClearColor(Color::TRANSPARENT);
+    captureData->mCaptureTask.SetRefreshRate(Dali::RenderTask::REFRESH_ONCE);
+
+    captureData->mCaptureInvertCamera = Dali::CameraActor::New(size);
+    captureData->mCaptureInvertCamera.SetProperty(Dali::Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT);
+    captureData->mCaptureInvertCamera.SetProperty(Dali::Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
+    captureData->mCaptureInvertCamera.SetProperty(Dali::Actor::Property::POSITION_X, size.x / 2.0f);
+    captureData->mCaptureInvertCamera.SetProperty(Dali::Actor::Property::POSITION_Y, size.y / 2.0f);
+
+    captureData->mCaptureUrl       = Dali::Toolkit::Image::GenerateUrl(captureData->mCaptureFrameBuffer, 0u);
+    captureData->mCaptureImageView = Dali::Toolkit::ImageView::New(captureData->mCaptureUrl.GetUrl());
+    captureData->mCaptureImageView.SetProperty(Dali::Actor::Property::SIZE, size);
+    captureData->mCaptureImageView.Add(captureData->mCaptureInvertCamera);
+
+    mSceneHolder.Add(captureData->mCaptureImageView);
+
+    captureData->mCaptureInvertTexture     = Dali::Texture::New(TextureType::TEXTURE_2D, Pixel::RGBA8888, width, height);
+    captureData->mCaptureInvertFrameBuffer = Dali::FrameBuffer::New(captureData->mCaptureInvertTexture.GetWidth(), captureData->mCaptureInvertTexture.GetHeight(), Dali::FrameBuffer::Attachment::DEPTH_STENCIL);
+    captureData->mCaptureInvertFrameBuffer.AttachColorTexture(captureData->mCaptureInvertTexture);
+
+    captureData->mCaptureInvertTask = taskList.CreateTask();
+    captureData->mCaptureInvertTask.SetSourceActor(captureData->mCaptureImageView);
+    captureData->mCaptureInvertTask.SetExclusive(true);
+    captureData->mCaptureInvertTask.SetCullMode(false);
+    captureData->mCaptureInvertTask.SetCameraActor(captureData->mCaptureInvertCamera);
+    captureData->mCaptureInvertTask.SetFrameBuffer(captureData->mCaptureInvertFrameBuffer);
+    captureData->mCaptureInvertTask.SetClearEnabled(true);
+    captureData->mCaptureInvertTask.SetClearColor(Color::TRANSPARENT);
+    captureData->mCaptureInvertTask.SetRefreshRate(Dali::RenderTask::REFRESH_ONCE);
+    captureData->mCaptureInvertTask.FinishedSignal().Connect(this, &SceneView::OnCaptureFinished);
+
+    captureData->mStartTick = mTimerTickCount;
+
+    mCaptureContainer.push_back(std::make_pair(captureData->mCaptureInvertTask, captureData));
+
+    if(!mCaptureTimer)
+    {
+      mCaptureTimer = Dali::Timer::New(1000);
+      mCaptureTimer.TickSignal().Connect(this, &SceneView::OnTimeOut);
+      mCaptureTimer.Start();
+    }
   }
   return mCaptureId++;
 }
@@ -1109,33 +1143,17 @@ void SceneView::OnSceneDisconnection()
   std::vector<std::pair<Dali::RenderTask, std::shared_ptr<CaptureData>>> tempContainer(mCaptureContainer);
   for(auto&& capture : tempContainer)
   {
-    Dali::Scene3D::SceneView::CaptureResult result{capture.second->mCaptureId, Dali::Toolkit::ImageUrl(), Dali::Scene3D::SceneView::CaptureFinishState::FAILED};
-    mCaptureFinishedSignal.Emit(handle, result);
+    mCaptureFinishedSignal.Emit(handle, capture.second->mCaptureId, Dali::Toolkit::ImageUrl());
   }
   tempContainer.clear();
 
   for(auto && capture : mCaptureContainer)
   {
-    if(mSceneHolder)
-    {
-      RenderTaskList taskList = mSceneHolder.GetRenderTaskList();
-      taskList.RemoveTask(capture.second->mCaptureTask);
-      taskList.RemoveTask(capture.second->mCaptureInvertTask);
-    }
-    capture.second->mCaptureTask.Reset();
-    capture.second->mCaptureInvertTask.Reset();
-    capture.second->mCaptureTexture.Reset();
-    capture.second->mCaptureInvertTexture.Reset();
-    capture.second->mCaptureFrameBuffer.Reset();
-    capture.second->mCaptureInvertFrameBuffer.Reset();
-    capture.second->mCaptureUrl.Reset();
-    capture.second->mCaptureImageView.Unparent();
-    capture.second->mCaptureImageView.Reset();
-    capture.second->mCaptureInvertCamera.Unparent();
-    capture.second->mCaptureInvertCamera.Reset();
+    ResetCaptureData(capture.second);
   }
   mCaptureContainer.clear();
 
+  ResetCaptureTimer();
 
   if(mSceneHolder)
   {
@@ -1508,44 +1526,25 @@ void SceneView::UpdateShadowMapBuffer(uint32_t shadowMapSize)
 
 void SceneView::OnCaptureFinished(Dali::RenderTask& task)
 {
-  int32_t                 captureId = INVALID_CAPTURE_ID;
-  Dali::Toolkit::ImageUrl imageUrl;
-
   auto iter = std::find_if(mCaptureContainer.begin(), mCaptureContainer.end(), [task](std::pair<Dali::RenderTask, std::shared_ptr<CaptureData>> item)
                            { return item.first == task; });
 
+  int32_t                 captureId = iter->second->mCaptureId;
+  Dali::Toolkit::ImageUrl imageUrl  = Dali::Toolkit::ImageUrl::New(iter->second->mCaptureInvertTexture);
+
   if(iter != mCaptureContainer.end())
   {
-    captureId               = iter->second->mCaptureId;
-    imageUrl                = Dali::Toolkit::ImageUrl::New(iter->second->mCaptureInvertTexture);
-    if(mSceneHolder)
-    {
-      RenderTaskList taskList = mSceneHolder.GetRenderTaskList();
-      taskList.RemoveTask(iter->second->mCaptureTask);
-      taskList.RemoveTask(iter->second->mCaptureInvertTask);
-    }
-    iter->second->mCaptureTexture.Reset();
-    iter->second->mCaptureInvertTexture.Reset();
-    iter->second->mCaptureFrameBuffer.Reset();
-    iter->second->mCaptureInvertFrameBuffer.Reset();
-    iter->second->mCaptureUrl.Reset();
-    iter->second->mCaptureImageView.Unparent();
-    iter->second->mCaptureImageView.Reset();
+    captureId = iter->second->mCaptureId;
+    imageUrl  = Dali::Toolkit::ImageUrl::New(iter->second->mCaptureInvertTexture);
+    ResetCaptureData(iter->second);
     mCaptureContainer.erase(iter);
 
     auto                     self = Self();
     Dali::Scene3D::SceneView handle(Dali::Scene3D::SceneView::DownCast(self));
-
-    Dali::Scene3D::SceneView::CaptureResult result{captureId, imageUrl, Dali::Scene3D::SceneView::CaptureFinishState::SUCCEEDED};
-    mCaptureFinishedSignal.Emit(handle, result);
+    mCaptureFinishedSignal.Emit(handle, captureId, imageUrl);
   }
 
-  if(mCaptureContainer.empty() && mCaptureTimer)
-  {
-    mCaptureTimer.Stop();
-    mCaptureTimer.Reset();
-    mTimerTickCount = 0;
-  }
+  ResetCaptureTimer();
 }
 
 bool SceneView::OnTimeOut()
@@ -1564,9 +1563,14 @@ bool SceneView::OnTimeOut()
 
   for(auto&& capture : tempContainer)
   {
-    Dali::Scene3D::SceneView::CaptureResult result{capture.second->mCaptureId, Dali::Toolkit::ImageUrl(), Dali::Scene3D::SceneView::CaptureFinishState::FAILED};
-    mCaptureFinishedSignal.Emit(handle, result);
+    mCaptureFinishedSignal.Emit(handle, capture.second->mCaptureId, Dali::Toolkit::ImageUrl());
+  }
+
+  for(auto && capture : tempContainer)
+  {
+    ResetCaptureData(capture.second);
   }
+  tempContainer.clear();
 
   int32_t tickCount = mTimerTickCount;
   auto it = std::remove_if(mCaptureContainer.begin(), mCaptureContainer.end(), [tickCount](std::pair<Dali::RenderTask, std::shared_ptr<CaptureData>> item) {
@@ -1575,14 +1579,52 @@ bool SceneView::OnTimeOut()
   mCaptureContainer.erase(it, mCaptureContainer.end());
   mCaptureContainer.shrink_to_fit();
 
+  ResetCaptureTimer();
+
+  return !mCaptureContainer.empty();
+}
+
+void SceneView::ResetCaptureData(std::shared_ptr<CaptureData> captureData)
+{
+  captureData->mCaptureCamera.SetAspectRatio(captureData->mCaptureCameraOriginalAspectRatio);
+  if(mSceneHolder)
+  {
+    RenderTaskList taskList = mSceneHolder.GetRenderTaskList();
+    taskList.RemoveTask(captureData->mCaptureTask);
+    taskList.RemoveTask(captureData->mCaptureInvertTask);
+  }
+  captureData->mCaptureTask.Reset();
+  captureData->mCaptureInvertTask.Reset();
+  captureData->mCaptureTexture.Reset();
+  captureData->mCaptureInvertTexture.Reset();
+  captureData->mCaptureFrameBuffer.Reset();
+  captureData->mCaptureInvertFrameBuffer.Reset();
+  captureData->mCaptureUrl.Reset();
+  captureData->mCaptureImageView.Unparent();
+  captureData->mCaptureImageView.Reset();
+  captureData->mCaptureInvertCamera.Unparent();
+  captureData->mCaptureInvertCamera.Reset();
+}
+
+void SceneView::ResetCaptureTimer()
+{
   if(mCaptureContainer.empty() && mCaptureTimer)
   {
     mCaptureTimer.Stop();
     mCaptureTimer.Reset();
     mTimerTickCount = 0;
   }
+}
 
-  return !mCaptureContainer.empty();
+void SceneView::OnCaptureFailedIdle()
+{
+  for(auto&& captureId : mFailedCaptureRequests)
+  {
+    auto                     self = Self();
+    Dali::Scene3D::SceneView handle(Dali::Scene3D::SceneView::DownCast(self));
+    mCaptureFinishedSignal.Emit(handle, captureId, Dali::Toolkit::ImageUrl());
+  }
+  mFailedCaptureCallbacks = nullptr;
 }
 
 } // namespace Internal
index 3c7d03086ebd829ede007342fd5b646b5caf4ebd..4ad8e6c7527fd0deb8a625d6b20667841fe31c65 100644 (file)
@@ -54,6 +54,26 @@ namespace Internal
 class SceneView : public Dali::Toolkit::Internal::Control
 {
 public:
+  /**
+   * Data to store Capture related objects.
+   */
+  struct CaptureData
+  {
+    int32_t                  mStartTick;
+    int32_t                  mCaptureId;                        // Unique Key to distinguish requested Captures.
+    float                    mCaptureCameraOriginalAspectRatio; // Original AspectRatio of the input cameras
+    Dali::Toolkit::ImageUrl  mCaptureUrl;                       // URL for first captured buffer, but it is Y-inverted.
+    Dali::Toolkit::ImageView mCaptureImageView;                 // ImageView to draw first capture buffer to be transfered as input for invert.
+    Dali::CameraActor        mCaptureCamera;                    // CameraActor to draw first capture buffer
+    Dali::RenderTask         mCaptureTask;                      // RenderTask that is used to capture first buffer.
+    Dali::Texture            mCaptureTexture;                   // First Captured texture, but it is Y-inverted.
+    Dali::FrameBuffer        mCaptureFrameBuffer;               // First Captured FBO, but it is Y-inverted.
+    Dali::CameraActor        mCaptureInvertCamera;              // CameraActor to invert first captured buffer by second pass.
+    Dali::RenderTask         mCaptureInvertTask;                // RenderTask to invert first captured buffer.
+    Dali::Texture            mCaptureInvertTexture;             // Result texture of second pass. This is final Texture result.
+    Dali::FrameBuffer        mCaptureInvertFrameBuffer;         // FBO for firnal Texture result
+  };
+
   /**
    * @brief Creates a new SceneView.
    *
@@ -454,25 +474,23 @@ private:
    */
   bool OnTimeOut();
 
-private:
   /**
-   * Data to store Capture related objects.
+   * @brief Reset CaptureData when the capture is finished or failed.
+   * @param[in] captureData CaptureData to be reset.
    */
-  struct CaptureData
-  {
-    int32_t                  mStartTick;
-    int32_t                  mCaptureId;                // Unique Key to distinguish requested Captures.
-    Dali::Toolkit::ImageUrl  mCaptureUrl;               // URL for first captured buffer, but it is Y-inverted.
-    Dali::Toolkit::ImageView mCaptureImageView;         // ImageView to draw first capture buffer to be transfered as input for invert.
-    Dali::RenderTask         mCaptureTask;              // RenderTask that is used to capture first buffer.
-    Dali::Texture            mCaptureTexture;           // First Captured texture, but it is Y-inverted.
-    Dali::FrameBuffer        mCaptureFrameBuffer;       // First Captured FBO, but it is Y-inverted.
-    Dali::CameraActor        mCaptureInvertCamera;      // CameraActor to invert first captured buffer by second pass.
-    Dali::RenderTask         mCaptureInvertTask;        // RenderTask to invert first captured buffer.
-    Dali::Texture            mCaptureInvertTexture;     // Result texture of second pass. This is final Texture result.
-    Dali::FrameBuffer        mCaptureInvertFrameBuffer; // FBO for firnal Texture result
-  };
+  void ResetCaptureData(std::shared_ptr<CaptureData> captureData);
+
+  /**
+   * @brief Reset Capture timer when there isn't any capture in progress.
+   */
+  void ResetCaptureTimer();
 
+  /**
+   * @brief Emit capture failed event on idle.
+   */
+  void OnCaptureFailedIdle();
+
+private:
   Toolkit::Visual::Base mVisual;
 
   /////////////////////////////////////////////////////////////
@@ -493,6 +511,8 @@ private:
   float                                               mSkyboxIntensity{1.0f};
   uint8_t                                             mFrameBufferMultiSamplingLevel{4u};
   Dali::Scene3D::SceneView::CaptureFinishedSignalType mCaptureFinishedSignal;
+  std::vector<int32_t>                                mFailedCaptureRequests;
+  CallbackBase*                                       mFailedCaptureCallbacks;
 
   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.
index 58ef5b57ae0759878e5690873b9d69a7aa0916d4..68b0015af3189d3ad0b671d70086d8b2bb9aab1b 100644 (file)
@@ -150,30 +150,11 @@ public:
     };
   };
 
-  /**
-   * @brief The enumerations used for checking capture success
-   * @SINCE_2_3.25
-   */
-  enum class CaptureFinishState
-  {
-    SUCCEEDED, ///< Succeeded to capture
-    FAILED     ///< Failed to capture by time out
-  };
-
 public:
-  struct CaptureResult
-  {
-    int32_t                 captureId;
-    Dali::Toolkit::ImageUrl imageUrl;
-    CaptureFinishState      state;
-  };
-
   /**
    * @brief Typedef for capture finished signals sent by this class.
-   *
-   * @SINCE_2_3.25
    */
-  typedef Signal<void(SceneView, CaptureResult&)> CaptureFinishedSignalType;
+  typedef Signal<void(SceneView, int32_t, const Dali::Toolkit::ImageUrl&)> CaptureFinishedSignalType;
 
   /**
    * @brief Create an initialized SceneView.
@@ -507,10 +488,11 @@ public:
   /**
    * @brief Requests to capture this SceneView with the Camera.
    *
-   * @SINCE_2_3.25
    * @param[in] camera CameraActor to be used for capture.
    * @param[in] size captured size.
-   * @note The camera is required to be added in this SceneView. (Not need to be a selected camera)
+   * @note The input camera should not be used for any other purpose during Capture.
+   * (Simultaneous usage elsewhere may result in incorrect rendering.)
+   * @note The camera is required to be added in this SceneView. (But should not be a selected camera.)
    * @note If the SceneView is disconnected from Scene, the left capture requests are canceled.
    * @return capture id that id unique value to distinguish each requiest.
    */
@@ -519,7 +501,6 @@ public:
   /**
    * @brief Get capture finished signal.
    *
-   * @SINCE_2_3.25
    * @return finished signal instance.
    */
   CaptureFinishedSignalType& CaptureFinishedSignal();