[Tizen] Calculrate screen position with RenderTask 64/281164/2
authorEunki, Hong <eunkiki.hong@samsung.com>
Mon, 5 Sep 2022 10:14:39 +0000 (19:14 +0900)
committerSeungho BAEK <sbsh.baek@samsung.com>
Wed, 14 Sep 2022 05:15:29 +0000 (05:15 +0000)
Previous ScreenPosition / ScreenExtents consider
only the scene's default camera.
Now we make a new API that consider Custom camera's
View/Projection matrix.

Calculate screen position & extents is quite heavy
operation. So we need to seperate it for
simple 2D layer or 3D layer.

So, we add mLayer3DParentsCount value in actor.
It will be generated when actor is scene on,
or some layer's behaviour changed during on scene.

TODO : Need to make UTC.

Change-Id: I7a6162bea84965f70800a6e7cbf2332e9933e20d
Signed-off-by: Eunki, Hong <eunkiki.hong@samsung.com>
dali/internal/event/actors/actor-coords.cpp
dali/internal/event/actors/actor-coords.h
dali/internal/event/actors/actor-impl.cpp
dali/internal/event/actors/actor-impl.h
dali/internal/event/actors/actor-parent-impl.cpp
dali/internal/event/actors/actor-parent-impl.h
dali/internal/event/actors/layer-impl.cpp

index 9d1010e..68bb0ed 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * 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.
@@ -136,7 +136,7 @@ const Vector2 CalculateActorScreenPosition(const Actor& actor, BufferIndex buffe
     worldPosition -= cameraPosition;
 
     Vector3 actorSize = node.GetSize(bufferIndex) * node.GetWorldScale(bufferIndex);
-    auto    sceneSize = scene.GetCurrentSurfaceRect();  // Use the update object's size
+    auto    sceneSize = scene.GetCurrentSurfaceRect();                      // Use the update object's size
     Vector2 halfSceneSize(sceneSize.width * 0.5f, sceneSize.height * 0.5f); // World position origin is center of scene
     Vector3 halfActorSize(actorSize * 0.5f);
     Vector3 anchorPointOffSet = halfActorSize - actorSize * actor.GetAnchorPointForPosition();
@@ -155,4 +155,300 @@ Rect<> CalculateActorScreenExtents(const Actor& actor, const Vector2& screenPosi
   return {position.x, position.y, size.x, size.y};
 }
 
+bool ConvertLocalToScreen(
+  const Matrix&  viewMatrix,
+  const Matrix&  projectionMatrix,
+  const Matrix&  worldMatrix,
+  const Rect<>&  viewportExtent,
+  const Vector3& localPosition,
+  float&         screenX,
+  float&         screenY)
+{
+  bool success = false;
+
+  // Convert local to projection coordinates
+  // note, P*(V*(M*pos))) is faster than (P*V*M)*pos
+  Vector4 mvpPos(localPosition.x, localPosition.y, localPosition.z, 1.0f);
+
+  mvpPos = worldMatrix * mvpPos;
+  mvpPos = viewMatrix * mvpPos;
+  mvpPos = projectionMatrix * mvpPos;
+
+  if(DALI_LIKELY(!EqualsZero(mvpPos.w)))
+  {
+    success = true;
+    screenX = viewportExtent.x + (mvpPos.x + mvpPos.w) * viewportExtent.width * 0.5f / mvpPos.w;
+    screenY = viewportExtent.y + (-mvpPos.y + mvpPos.w) * viewportExtent.height * 0.5f / mvpPos.w;
+  }
+  return success;
+}
+
+bool ConvertLocalToScreenRenderTask(
+  const RenderTask& renderTask,
+  const Actor&      actor,
+  const Matrix&     worldMatrix,
+  const Vector3&    localPosition,
+  float&            screenX,
+  float&            screenY)
+{
+  bool         success     = false;
+  const Actor* sourceActor = renderTask.GetSourceActor();
+  if(sourceActor == nullptr)
+  {
+    return success;
+  }
+
+  // Check whether current actor is in this rendertask.
+  bool         actorInRendertask = false;
+  const Actor* targetActor       = &actor;
+  while(targetActor)
+  {
+    if(sourceActor == targetActor)
+    {
+      actorInRendertask = true;
+      break;
+    }
+    targetActor = targetActor->GetParent();
+  }
+  if(!actorInRendertask)
+  {
+    return success;
+  }
+
+  CameraActor* camera = renderTask.GetCameraActor();
+  if(camera)
+  {
+    Rect<float> viewportExtent = {0.f, 0.f, 0.f, 0.f};
+    if(renderTask.GetFrameBuffer())
+    {
+      Dali::Actor mappingActor = renderTask.GetScreenToFrameBufferMappingActor();
+      if(mappingActor)
+      {
+        // NOTE : We will assume that mapping actor always use default camera.
+        Vector2 screenPosition    = mappingActor.GetProperty<Vector2>(Dali::Actor::Property::SCREEN_POSITION);
+        Vector3 size              = mappingActor.GetCurrentProperty<Vector3>(Dali::Actor::Property::SIZE) * mappingActor.GetCurrentProperty<Vector3>(Dali::Actor::Property::WORLD_SCALE);
+        Vector3 anchorPointOffSet = size * GetImplementation(mappingActor).GetAnchorPointForPosition();
+        Vector2 position          = Vector2(screenPosition.x - anchorPointOffSet.x, screenPosition.y - anchorPointOffSet.y);
+        viewportExtent.x          = position.x;
+        viewportExtent.y          = position.y;
+        viewportExtent.width      = size.x;
+        viewportExtent.height     = size.y;
+      }
+      else
+      {
+        return success;
+      }
+    }
+    else
+    {
+      Viewport viewport;
+      renderTask.GetViewport(viewport);
+      viewportExtent.x      = viewport.x;
+      viewportExtent.y      = viewport.y;
+      viewportExtent.width  = viewport.width;
+      viewportExtent.height = viewport.height;
+    }
+
+    if(ConvertLocalToScreen(camera->GetViewMatrix(), camera->GetProjectionMatrix(), worldMatrix, viewportExtent, localPosition, screenX, screenY))
+    {
+      success = true;
+    }
+  }
+  return success;
+}
+
+bool ConvertLocalToScreenRenderTaskList(
+  const RenderTaskList& renderTaskList,
+  const Actor&          actor,
+  const Matrix&         worldMatrix,
+  const Vector3&        localPosition,
+  float&                screenX,
+  float&                screenY)
+{
+  // do a reverse traversal of all lists (as the default onscreen one is typically the last one)
+  uint32_t taskCount = renderTaskList.GetTaskCount();
+  for(uint32_t i = taskCount; i > 0; --i)
+  {
+    RenderTaskPtr task = renderTaskList.GetTask(i - 1);
+    if(ConvertLocalToScreenRenderTask(*task, actor, worldMatrix, localPosition, screenX, screenY))
+    {
+      // found a task where this conversion was ok so return
+      return true;
+    }
+  }
+  return false;
+}
+
+const Vector2 CalculateActorScreenPositionRenderTaskList(const Actor& actor, BufferIndex bufferIndex)
+{
+  if(actor.OnScene())
+  {
+    const auto& node  = actor.GetNode();
+    Scene&      scene = actor.GetScene();
+
+    Vector2 result;
+
+    auto        worldMatrix    = node.GetWorldMatrix(bufferIndex);
+    const auto& renderTaskList = scene.GetRenderTaskList();
+    ConvertLocalToScreenRenderTaskList(renderTaskList, actor, worldMatrix, node.GetSize(bufferIndex) * (actor.GetAnchorPointForPosition() - Vector3(0.5f, 0.5f, 0.5f)), result.x, result.y);
+
+    return result;
+  }
+  return Vector2::ZERO;
+}
+
+bool ConvertLocalToScreenExtentRenderTask(
+  const RenderTask& renderTask,
+  const Actor&      actor,
+  const Matrix&     worldMatrix,
+  const Vector3&    currentSize,
+  Rect<>&           screenExtent)
+{
+  bool         success     = false;
+  const Actor* sourceActor = renderTask.GetSourceActor();
+  if(sourceActor == nullptr)
+  {
+    return success;
+  }
+
+  // Check whether current actor is in this rendertask.
+  bool         actorInRendertask = false;
+  const Actor* targetActor       = &actor;
+  while(targetActor)
+  {
+    if(sourceActor == targetActor)
+    {
+      actorInRendertask = true;
+      break;
+    }
+    targetActor = targetActor->GetParent();
+  }
+  if(!actorInRendertask)
+  {
+    return success;
+  }
+
+  CameraActor* camera = renderTask.GetCameraActor();
+  if(camera)
+  {
+    Rect<float> viewportExtent = {0.f, 0.f, 0.f, 0.f};
+    if(renderTask.GetFrameBuffer())
+    {
+      Dali::Actor mappingActor = renderTask.GetScreenToFrameBufferMappingActor();
+      if(mappingActor)
+      {
+        // NOTE : We will assume that mapping actor always use default camera.
+        Vector2 screenPosition    = mappingActor.GetProperty<Vector2>(Dali::Actor::Property::SCREEN_POSITION);
+        Vector3 size              = mappingActor.GetCurrentProperty<Vector3>(Dali::Actor::Property::SIZE) * mappingActor.GetCurrentProperty<Vector3>(Dali::Actor::Property::WORLD_SCALE);
+        Vector3 anchorPointOffSet = size * GetImplementation(mappingActor).GetAnchorPointForPosition();
+        Vector2 position          = Vector2(screenPosition.x - anchorPointOffSet.x, screenPosition.y - anchorPointOffSet.y);
+        viewportExtent.x          = position.x;
+        viewportExtent.y          = position.y;
+        viewportExtent.width      = size.x;
+        viewportExtent.height     = size.y;
+      }
+      else
+      {
+        return success;
+      }
+    }
+    else
+    {
+      Viewport viewport;
+      renderTask.GetViewport(viewport);
+      viewportExtent.x      = viewport.x;
+      viewportExtent.y      = viewport.y;
+      viewportExtent.width  = viewport.width;
+      viewportExtent.height = viewport.height;
+    }
+
+    constexpr uint32_t BOX_POINT_COUNT           = 8;
+    const Vector3      BBOffset[BOX_POINT_COUNT] = {
+      Vector3(-currentSize.width * 0.5f, -currentSize.height * 0.5f, -currentSize.depth * 0.5f),
+      Vector3(-currentSize.width * 0.5f, currentSize.height * 0.5f, -currentSize.depth * 0.5f),
+      Vector3(currentSize.width * 0.5f, -currentSize.height * 0.5f, -currentSize.depth * 0.5f),
+      Vector3(currentSize.width * 0.5f, currentSize.height * 0.5f, -currentSize.depth * 0.5f),
+      Vector3(-currentSize.width * 0.5f, -currentSize.height * 0.5f, currentSize.depth * 0.5f),
+      Vector3(-currentSize.width * 0.5f, currentSize.height * 0.5f, currentSize.depth * 0.5f),
+      Vector3(currentSize.width * 0.5f, -currentSize.height * 0.5f, currentSize.depth * 0.5f),
+      Vector3(currentSize.width * 0.5f, currentSize.height * 0.5f, currentSize.depth * 0.5f),
+    };
+
+    float minScreenX;
+    float minScreenY;
+    float maxScreenX;
+    float maxScreenY;
+
+    const auto& viewMatrix       = camera->GetViewMatrix();
+    const auto& projectionMatrix = camera->GetProjectionMatrix();
+
+    success = ConvertLocalToScreen(viewMatrix, projectionMatrix, worldMatrix, viewportExtent, BBOffset[0], minScreenX, minScreenY);
+    if(success)
+    {
+      maxScreenX = minScreenX;
+      maxScreenY = minScreenY;
+      for(uint32_t i = 1; i < BOX_POINT_COUNT; ++i)
+      {
+        float   screenX;
+        float   screenY;
+        Vector3 localPosition = BBOffset[i];
+        if(DALI_UNLIKELY(!ConvertLocalToScreen(viewMatrix, projectionMatrix, worldMatrix, viewportExtent, localPosition, screenX, screenY)))
+        {
+          success = false;
+          break;
+        }
+        minScreenX = std::min(minScreenX, screenX);
+        maxScreenX = std::max(maxScreenX, screenX);
+        minScreenY = std::min(minScreenY, screenY);
+        maxScreenY = std::max(maxScreenY, screenY);
+      }
+      if(success)
+      {
+        screenExtent.x      = minScreenX;
+        screenExtent.y      = minScreenY;
+        screenExtent.width  = maxScreenX - minScreenX;
+        screenExtent.height = maxScreenY - minScreenY;
+      }
+    }
+  }
+  return success;
+}
+
+bool ConvertLocalToScreenExtentRenderTaskList(
+  const RenderTaskList& renderTaskList,
+  const Actor&          actor,
+  const Matrix&         worldMatrix,
+  const Vector3&        currentSize,
+  Rect<>&               screenExtent)
+{
+  // do a reverse traversal of all lists (as the default onscreen one is typically the last one)
+  uint32_t taskCount = renderTaskList.GetTaskCount();
+  for(uint32_t i = taskCount; i > 0; --i)
+  {
+    RenderTaskPtr task = renderTaskList.GetTask(i - 1);
+    if(ConvertLocalToScreenExtentRenderTask(*task, actor, worldMatrix, currentSize, screenExtent))
+    {
+      // found a task where this conversion was ok so return
+      return true;
+    }
+  }
+  return false;
+}
+
+Rect<> CalculateActorScreenExtentsRenderTaskList(const Actor& actor, BufferIndex bufferIndex)
+{
+  Rect<> result = {0.0f, 0.0f, 0.0f, 0.0f};
+
+  if(actor.OnScene())
+  {
+    const auto& node  = actor.GetNode();
+    Scene&      scene = actor.GetScene();
+
+    auto        worldMatrix    = node.GetWorldMatrix(bufferIndex);
+    const auto& renderTaskList = scene.GetRenderTaskList();
+    ConvertLocalToScreenExtentRenderTaskList(renderTaskList, actor, worldMatrix, node.GetSize(bufferIndex), result);
+  }
+  return result;
+}
+
 } // namespace Dali::Internal
index d6ebd36..f844204 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_INTERNAL_EVENT_ACTORS_ACTOR_COORDS_H
 
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * 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.
@@ -32,8 +32,8 @@ namespace Dali::Internal
  * @param[in] viewMatrix The view matrix used to display this entity
  * @param[in] projectionMatrix The projection matrix used to display this entity
  * @param[in] worldMatrix The world matrix of this entity
- * @param[in] viewport The viewport used for drawing
  * @param[in] currentSize The 2d bounding box for this entity
+ * @param[in] viewport The viewport used for drawing
  * @param[out] localX The local X coordinate
  * @param[out] localY The local Y coordinate
  * @param[in] screenX The screen X coordinate
@@ -112,6 +112,119 @@ const Vector2 CalculateActorScreenPosition(const Actor& actor, BufferIndex buffe
  */
 Rect<> CalculateActorScreenExtents(const Actor& actor, const Vector2& screenPosition, BufferIndex bufferIndex);
 
+/**
+ * Convert local coordinates to screen coordinates
+ *
+ * @param[in] viewMatrix The view matrix used to display this entity
+ * @param[in] projectionMatrix The projection matrix used to display this entity
+ * @param[in] worldMatrix The world matrix of this entity
+ * @param[in] viewport The viewport used for drawing
+ * @param[in] localPosition The local position
+ * @param[out] screenX The screen X coordinate
+ * @param[out] screenY The screen Y coordinate
+ * @return true if the conversion was successful
+ */
+bool ConvertLocalToScreen(const Matrix&   viewMatrix,
+                          const Matrix&   projectionMatrix,
+                          const Matrix&   worldMatrix,
+                          const Viewport& viewport,
+                          const Vector3&  localPosition,
+                          float&          screenX,
+                          float&          screenY);
+
+/**
+ * Convert local coordinates to screen coordinates
+ *
+ * @param[in] renderTask The render task used to display this entity
+ * @param[in] actor The actor of this entity
+ * @param[in] worldMatrix The world matrix of this entity
+ * @param[in] localPosition The local position
+ * @param[out] screenX The screen X coordinate
+ * @param[out] screenY The screen Y coordinate
+ * @return true if the conversion was successful
+ */
+bool ConvertLocalToScreenRenderTask(
+  const RenderTask& renderTask,
+  const Actor&      actor,
+  const Matrix&     worldMatrix,
+  const Vector3&    localPosition,
+  float&            screenX,
+  float&            screenY);
+
+/**
+ * Convert local coordinates to screen coordinates
+ * Search through the given renderTaskList to check if this entity can be converted
+ *
+ * @param[in] renderTaskList The render task list to search
+ * @param[in] actor The actor of this entity
+ * @param[in] worldMatrix The world matrix of this entity
+ * @param[in] localPosition The local position
+ * @param[out] screenX The screen X coordinate
+ * @param[out] screenY The screen Y coordinate
+ * @return true if the conversion was successful
+ */
+bool ConvertLocalToScreenRenderTaskList(
+  const RenderTaskList& renderTaskList,
+  const Actor&          actor,
+  const Matrix&         worldMatrix,
+  const Vector3&        localPosition,
+  float&                screenX,
+  float&                screenY);
+
+/**
+ * Calculate the screen position of the actor from it's node transform and anchor point.
+ * It will consider rendertasklist.
+ *
+ * @param[in] actor The actor
+ * @param[in] bufferIndex The current event buffer index
+ * @return the screen extents of the actor consider camera.
+ */
+const Vector2 CalculateActorScreenPositionRenderTaskList(const Actor& actor, BufferIndex bufferIndex);
+
+/**
+ * Convert local coordinates to screen coordinates extent
+ *
+ * @param[in] renderTask The render task used to display this entity
+ * @param[in] actor The actor of this entity
+ * @param[in] worldMatrix The world matrix of this entity
+ * @param[in] localPosition The local position
+ * @param[out] screenExtent The screen Extent
+ * @return true if the conversion was successful
+ */
+bool ConvertLocalToScreenExtentRenderTask(
+  const RenderTask& renderTask,
+  const Actor&      actor,
+  const Matrix&     worldMatrix,
+  const Vector3&    currentSize,
+  Rect<>&           screenExtent);
+
+/**
+ * Convert local coordinates to screen coordinates extent
+ * Search through the given renderTaskList to check if this entity can be converted
+ *
+ * @param[in] renderTaskList The render task list to search
+ * @param[in] actor The actor of this entity
+ * @param[in] worldMatrix The world matrix of this entity
+ * @param[in] localPosition The local position
+ * @param[out] screenExtent The screen Extent
+ * @return true if the conversion was successful
+ */
+bool ConvertLocalToScreenExtentRenderTaskList(
+  const RenderTaskList& renderTaskList,
+  const Actor&          actor,
+  const Matrix&         worldMatrix,
+  const Vector3&        currentSize,
+  Rect<>&               screenExtent);
+/**
+ * Calculate the screen extents of the actor from its node transform, anchor point and size.
+ * It will consider rendertasklist.
+ *
+ * @param[in] actor The actor
+ * @param[in] bufferIndex The current event buffer index
+ * @return the screen extents of the actor consider camera.
+ */
+Rect<> CalculateActorScreenExtentsRenderTaskList(const Actor& actor, BufferIndex bufferIndex);
+
 } // namespace Dali::Internal
 
 #endif // DALI_INTERNAL_EVENT_ACTORS_ACTOR_COORDS_H
index 4414f1d..3cef7cb 100644 (file)
@@ -540,7 +540,15 @@ const Vector2 Actor::GetCurrentScreenPosition() const
   if(mScene)
   {
     BufferIndex bufferIndex = GetEventThreadServices().GetEventBufferIndex();
-    return CalculateActorScreenPosition(*this, bufferIndex);
+    if(mLayer3DParentsCount == 0)
+    {
+      // We can assume that this actor is under 2d layer. Use faster, but imprecise algorithm
+      return CalculateActorScreenPosition(*this, bufferIndex);
+    }
+    else
+    {
+      return CalculateActorScreenPositionRenderTaskList(*this, bufferIndex);
+    }
   }
   return Vector2::ZERO;
 }
@@ -1195,7 +1203,7 @@ void Actor::UnparentChildren()
   mParentImpl.UnparentChildren();
 }
 
-void Actor::ConnectToScene(uint32_t parentDepth, bool notify)
+void Actor::ConnectToScene(uint32_t parentDepth, uint32_t layer3DParentsCount, bool notify)
 {
   // This container is used instead of walking the Actor hierarchy.
   // It protects us when the Actor hierarchy is modified during OnSceneConnectionExternal callbacks.
@@ -1207,7 +1215,7 @@ void Actor::ConnectToScene(uint32_t parentDepth, bool notify)
   }
 
   // This stage is not interrupted by user callbacks.
-  mParentImpl.RecursiveConnectToScene(connectionList, parentDepth + 1);
+  mParentImpl.RecursiveConnectToScene(connectionList, layer3DParentsCount, parentDepth + 1);
 
   // Notify applications about the newly connected actors.
   for(const auto& actor : connectionList)
@@ -1476,7 +1484,7 @@ void Actor::SetParent(ActorParent* parent, bool notify)
        parentActor->OnScene())
     {
       // Instruct each actor to create a corresponding node in the scene graph
-      ConnectToScene(parentActor->GetHierarchyDepth(), notify);
+      ConnectToScene(parentActor->GetHierarchyDepth(), parentActor->GetLayer3DParentCount(), notify);
     }
 
     // Resolve the name and index for the child properties if any
@@ -1504,9 +1512,18 @@ void Actor::SetParent(ActorParent* parent, bool notify)
 
 Rect<> Actor::CalculateScreenExtents() const
 {
-  auto        screenPosition = GetCurrentScreenPosition();
-  BufferIndex bufferIndex    = GetEventThreadServices().GetEventBufferIndex();
-  return CalculateActorScreenExtents(*this, screenPosition, bufferIndex);
+  if(mLayer3DParentsCount == 0)
+  {
+    // We can assume that this actor is under 2d layer. Use faster, but imprecise algorithm
+    auto        screenPosition = GetCurrentScreenPosition();
+    BufferIndex bufferIndex    = GetEventThreadServices().GetEventBufferIndex();
+    return CalculateActorScreenExtents(*this, screenPosition, bufferIndex);
+  }
+  else
+  {
+    BufferIndex bufferIndex = GetEventThreadServices().GetEventBufferIndex();
+    return CalculateActorScreenExtentsRenderTaskList(*this, bufferIndex);
+  }
 }
 
 Vector3 Actor::GetAnchorPointForPosition() const
index d0d985f..4557a03 100644 (file)
@@ -767,6 +767,21 @@ public:
   }
 
   /**
+   * @brief Get the number of layer with 3D behaviour in ancestors include this. It will be 0 if actor is not on scene.
+   *
+   * @return currently the number of layer with 3D behaviour in ancestors.
+   */
+  inline int32_t GetLayer3DParentCount() const
+  {
+    if(mIsOnScene)
+    {
+      return mLayer3DParentsCount;
+    }
+
+    return 0;
+  }
+
+  /**
    * Get the actor's sorting depth
    *
    * @return The depth used for hit-testing and renderer sorting
@@ -1538,9 +1553,10 @@ protected:
   /**
    * Called on a child during Add() when the parent actor is connected to the Scene.
    * @param[in] parentDepth The depth of the parent in the hierarchy.
+   * @param[in] layer3DParentsCount The number of 3d layers in the hierarchy.
    * @param[in] notify Emits notification if set to true.
    */
-  void ConnectToScene(uint32_t parentDepth, bool notify);
+  void ConnectToScene(uint32_t parentDepth, uint32_t layer3DParentsCount, bool notify);
 
   /**
    * Connect the Node associated with this Actor to the scene-graph.
@@ -1914,6 +1930,8 @@ protected:
   uint32_t    mSortedDepth; ///< The sorted depth index. A combination of tree traversal and sibling order.
   int16_t     mDepth;       ///< The depth in the hierarchy of the actor. Only 32,767 levels of depth are supported
 
+  int16_t mLayer3DParentsCount; ///< The number of layer with 3D behaviour in ancestors include this. It will be 0 if actor is not on scene.
+
   const bool               mIsRoot : 1;                    ///< Flag to identify the root actor
   const bool               mIsLayer : 1;                   ///< Flag to identify that this is a layer
   bool                     mIsOnScene : 1;                 ///< Flag to identify whether the actor is on-scene
index f5311df..781b1b7 100644 (file)
@@ -433,12 +433,22 @@ void ActorParentImpl::DepthTraverseActorTree(OwnerPointer<SceneGraph::NodeDepths
   }
 }
 
-void ActorParentImpl::RecursiveConnectToScene(ActorContainer& connectionList, uint32_t depth)
+void ActorParentImpl::RecursiveConnectToScene(ActorContainer& connectionList, uint32_t layer3DParentsCount, uint32_t depth)
 {
   DALI_ASSERT_ALWAYS(!mOwner.OnScene());
 
-  mOwner.mIsOnScene = true;
-  mOwner.mDepth     = static_cast<uint16_t>(depth); // overflow ignored, not expected in practice
+  if(mOwner.mIsLayer)
+  {
+    if(static_cast<Dali::Internal::Layer*>(&mOwner)->GetBehavior() == Dali::Layer::Behavior::LAYER_3D)
+    {
+      // This is 3d layer. Propagate it to all children.
+      ++layer3DParentsCount;
+    }
+  }
+
+  mOwner.mIsOnScene           = true;
+  mOwner.mDepth               = static_cast<uint16_t>(depth);               // overflow ignored, not expected in practice
+  mOwner.mLayer3DParentsCount = static_cast<uint16_t>(layer3DParentsCount); // overflow ignored, not expected in practice
   mOwner.ConnectToSceneGraph();
 
   // Notification for internal derived classes
@@ -453,7 +463,7 @@ void ActorParentImpl::RecursiveConnectToScene(ActorContainer& connectionList, ui
     for(const auto& actor : *mChildren)
     {
       actor->SetScene(*mOwner.mScene);
-      actor->mParentImpl.RecursiveConnectToScene(connectionList, depth + 1);
+      actor->mParentImpl.RecursiveConnectToScene(connectionList, layer3DParentsCount, depth + 1);
     }
   }
 }
@@ -461,8 +471,9 @@ void ActorParentImpl::RecursiveConnectToScene(ActorContainer& connectionList, ui
 void ActorParentImpl::RecursiveDisconnectFromScene(ActorContainer& disconnectionList)
 {
   // need to change state first so that internals relying on IsOnScene() inside OnSceneDisconnectionInternal() get the correct value
-  mOwner.mIsOnScene = false;
-  mOwner.mScene     = nullptr;
+  mOwner.mIsOnScene           = false;
+  mOwner.mScene               = nullptr;
+  mOwner.mLayer3DParentsCount = 0;
 
   // Recursively disconnect children
   if(mChildren)
@@ -481,6 +492,20 @@ void ActorParentImpl::RecursiveDisconnectFromScene(ActorContainer& disconnection
   mOwner.DisconnectFromSceneGraph();
 }
 
+void ActorParentImpl::RecursiveChangeLayer3dCount(int32_t layer3DParentsCountDiff)
+{
+  mOwner.mLayer3DParentsCount += layer3DParentsCountDiff; // overflow ignored, not expected in practice
+
+  // Recursively change the value
+  if(mChildren)
+  {
+    for(const auto& actor : *mChildren)
+    {
+      actor->mParentImpl.RecursiveChangeLayer3dCount(layer3DParentsCountDiff);
+    }
+  }
+}
+
 void ActorParentImpl::InheritLayoutDirectionRecursively(Dali::LayoutDirection::Type direction, bool set)
 {
   if(mOwner.mInheritLayoutDirection || set)
index 5dff226..c284953 100644 (file)
@@ -1,7 +1,7 @@
 #ifndef DALI_INTERNAL_ACTOR_PARENT_IMPL_H
 #define DALI_INTERNAL_ACTOR_PARENT_IMPL_H
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use actor file except in compliance with the License.
@@ -205,9 +205,10 @@ public:
    * Helper to recursively connect a tree of actors.
    * This is not interrupted by user callbacks
    * @param[in]  depth The depth in the hierarchy of the actor
+   * @param[in]  layer3DParentsCount The number of 3d layers in the hierarchy.
    * @param[out] connectionList On return, the list of connected actors which require notification.
    */
-  void RecursiveConnectToScene(ActorContainer& connectionList, uint32_t depth);
+  void RecursiveConnectToScene(ActorContainer& connectionList, uint32_t layer3DParentsCount, uint32_t depth);
 
   /**
    * Helper to recursively disconnect a tree of actors.
@@ -217,6 +218,13 @@ public:
   void RecursiveDisconnectFromScene(ActorContainer& disconnectionList);
 
   /**
+   * Helper to recursively change the number of 3d layers in a tree of actors.
+   * This is not interrupted by user callbacks.
+   * @param[in] layer3DParentsCountDiff Difference valaue of 3d layers count.
+   */
+  void RecursiveChangeLayer3dCount(int32_t layer3DParentsCountDiff);
+
+  /**
    * @brief Propagates layout direction recursively.
    * @param[in] direction New layout direction.
    */
index bc0ad28..d0d7e23 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * 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.
@@ -239,12 +239,22 @@ void Layer::MoveBelow(const Internal::Layer& target)
 
 void Layer::SetBehavior(Dali::Layer::Behavior behavior)
 {
-  mBehavior = behavior;
+  if(mBehavior != behavior)
+  {
+    mBehavior = behavior;
 
-  // Notify update side object.
-  SetBehaviorMessage(GetEventThreadServices(), GetSceneGraphLayer(), behavior);
-  // By default, disable depth test for LAYER_UI, and enable for LAYER_3D.
-  SetDepthTestDisabled(mBehavior == Dali::Layer::LAYER_UI);
+    if(mIsOnScene)
+    {
+      // If current layer is on scene, and it's behavior changed,
+      // Change the mLayer3DParentsCount value recursively.
+      mParentImpl.RecursiveChangeLayer3dCount(mBehavior == Dali::Layer::LAYER_3D ? 1 : -1);
+    }
+
+    // Notify update side object.
+    SetBehaviorMessage(GetEventThreadServices(), GetSceneGraphLayer(), behavior);
+    // By default, disable depth test for LAYER_UI, and enable for LAYER_3D.
+    SetDepthTestDisabled(mBehavior == Dali::Layer::LAYER_UI);
+  }
 }
 
 void Layer::SetClipping(bool enabled)