Remove duplicate codes for screen position
[platform/core/uifw/dali-core.git] / dali / internal / event / actors / actor-coords.cpp
index 9d1010e..706a6b9 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2023 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#include <dali/internal/common/matrix-utils.h>
 #include <dali/internal/event/actors/actor-coords.h>
 #include <dali/internal/event/common/event-thread-services.h>
 #include <dali/internal/event/common/projection.h>
 
 namespace Dali::Internal
 {
+namespace
+{
+/**
+ * @brief Get the Viewport Extents from RenderTask
+ *
+ * @param[in] renderTask RenderTask what we want to get viewport.
+ * @param[out] viewportExtent Calculated extent by renderTask.
+ * @return True if we success to get viewports. False otherwise
+ */
+bool GetViewportExtentsFromRenderTask(const RenderTask& renderTask, Rect<float>& viewportExtent)
+{
+  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 false;
+    }
+  }
+  else
+  {
+    Viewport viewport;
+    renderTask.GetViewport(viewport);
+    viewportExtent.x      = viewport.x;
+    viewportExtent.y      = viewport.y;
+    viewportExtent.width  = viewport.width;
+    viewportExtent.height = viewport.height;
+  }
+  return true;
+}
+
+/**
+ * @brief Get the Orientation from Forward vector and Up vector
+ * If vectors are valid, return Quaternion to make forward direction as +Z, and up direction near as -Y axis.
+ * If some invalid vector inputed (like Zero length, or parallel vector), return identity quaternion
+ *
+ * @param[in] forward The vector that want to be +Z axis.
+ * @param[in] up The vector that want to be -Y axis.
+ * @return Quaternion to make forward direction as +Z, and up direction near as -Y axis.
+ */
+Quaternion GetOrientationFromForwardAndUpVector(Vector3 forward, Vector3 up)
+{
+  Vector3 vZ = forward;
+  vZ.Normalize();
+
+  Vector3 vX = up.Cross(vZ);
+  vX.Normalize();
+
+  // If something invalid input comes, vX length become zero.
+  if(DALI_UNLIKELY(Dali::EqualsZero(vX.Length())))
+  {
+    DALI_LOG_ERROR("Invalid value inputed, forward : %f %f %f ,  up : %f %f %f\n", forward.x, forward.y, forward.z, up.x, up.y, up.z);
+    return Quaternion();
+  }
+
+  Vector3 vY = vZ.Cross(vX);
+  vY.Normalize();
+
+  return Quaternion(vX, vY, vZ);
+}
+
+// Common API for calculating screen position
+
+/**
+ * @brief Retrieve actor's world position by Event related properties after calculating the world transform matrix.
+ *
+ * @param[in] actor The actor that wants to get WorldPosition
+ * @param[out] worldTransformMatrix Calculated world matrix as output. We can reuse this value in other logics.
+ * @return Calculated world position
+ */
+Vector3 RetrieveCalculatedWorldPosition(const Actor& actor, Matrix& worldTransformMatrix)
+{
+  worldTransformMatrix = Dali::Internal::CalculateActorWorldTransform(actor);
+
+  Scene& scene = actor.GetScene();
+
+  Vector3 worldPosition  = worldTransformMatrix.GetTranslation3();
+  Vector3 cameraPosition = Dali::Internal::CalculateActorWorldTransform(scene.GetDefaultCameraActor()).GetTranslation3();
+  worldPosition -= cameraPosition;
+
+  return worldPosition;
+}
+
+/**
+ * @brief Calculate actor's current world position by Update related properties.
+ *
+ * @param[in] actor The actor that wants to get WorldPosition
+ * @param[in] bufferIndex Buffer index of update
+ * @return Calculated world position
+ */
+Vector3 CalculateCurrentWorldPosition(const Actor& actor, BufferIndex bufferIndex)
+{
+  Scene& scene = actor.GetScene();
+
+  Vector3 worldPosition  = actor.GetNode().GetWorldPosition(bufferIndex);
+  Vector3 cameraPosition = scene.GetDefaultCameraActor().GetNode().GetWorldPosition(bufferIndex);
+  worldPosition -= cameraPosition;
+
+  return worldPosition;
+}
+
+/**
+ * @brief Calculate actor's scaled size by world scale.
+ *
+ * @param[in] actor The actor that wants to get scaled size
+ * @param[in] worldTransformMatrix The actor's world matrix
+ * @return The size scaled by world scale
+ */
+Vector3 CalculateScaledActorSize(const Actor& actor, const Matrix& worldTransformMatrix)
+{
+  return actor.GetTargetSize() * worldTransformMatrix.GetScale();
+}
+
+/**
+ * @brief Calculate actor's current scaled size by world scale.
+ *
+ * @param[in] actor The actor that wants to get scaled size
+ * @param[in] bufferIndex Buffer index of update
+ * @return The size scaled by world scale
+ */
+Vector3 CalculateCurrentScaledActorSize(const Actor& actor, BufferIndex bufferIndex)
+{
+  auto& node = actor.GetNode();
+  return node.GetSize(bufferIndex) * node.GetWorldScale(bufferIndex);
+}
+
+/**
+ * @brief Calculate screen extents top-left point position
+ *
+ * @param[in] sceneSize The scene size
+ * @param[in] actorSize The actor size
+ * @param[in] worldPosition The actor's world position
+ * @return The size scaled by world scale
+ */
+template<typename SceneSizeType, typename ActorSizeType, typename WorldPositionType>
+Vector2 CalculateActorTopLeftScreenPosition(const SceneSizeType& sceneSize, const ActorSizeType& actorSize, const WorldPositionType& worldPosition)
+{
+  const Vector2 halfSceneSize(sceneSize.width * 0.5f, sceneSize.height * 0.5f);
+  const Vector2 halfActorSize(actorSize.width * 0.5f, actorSize.height * 0.5f);
+
+  return Vector2(halfSceneSize.width - halfActorSize.width + worldPosition.x, halfSceneSize.height - halfActorSize.height + worldPosition.y);
+}
+} // namespace
+
 bool ConvertScreenToLocal(
   const Matrix&   viewMatrix,
   const Matrix&   projectionMatrix,
@@ -35,11 +192,11 @@ bool ConvertScreenToLocal(
 {
   // Get the ModelView matrix
   Matrix modelView;
-  Matrix::Multiply(modelView, worldMatrix, viewMatrix);
+  MatrixUtils::MultiplyTransformMatrix(modelView, worldMatrix, viewMatrix);
 
   // Calculate the inverted ModelViewProjection matrix; this will be used for 2 unprojects
   Matrix invertedMvp(false /*don't init*/);
-  Matrix::Multiply(invertedMvp, modelView, projectionMatrix);
+  MatrixUtils::MultiplyProjectionMatrix(invertedMvp, modelView, projectionMatrix);
   bool success = invertedMvp.Invert();
 
   // Convert to GL coordinates
@@ -123,36 +280,566 @@ bool ConvertScreenToLocalRenderTaskList(
     }
   }
   return false;
-};
+}
 
-const Vector2 CalculateActorScreenPosition(const Actor& actor, BufferIndex bufferIndex)
+const Vector2 CalculateActorScreenPosition(const Actor& actor)
 {
-  Scene& scene = actor.GetScene();
+  Vector2 result;
+  if(actor.OnScene())
+  {
+    Matrix worldTransformMatrix(false); // Do not initialize. It will be calculated in RetrieveCalculatedWorldPosition API.
+
+    Vector3 worldPosition = RetrieveCalculatedWorldPosition(actor, worldTransformMatrix);
+    Vector3 actorSize     = CalculateScaledActorSize(actor, worldTransformMatrix);
+
+    auto sceneSize = actor.GetScene().GetSize();
+
+    Vector2 screenPositionTopLeft = CalculateActorTopLeftScreenPosition(sceneSize, actorSize, worldPosition);
+    Vector2 anchorPointOffSet     = (actorSize * actor.GetAnchorPointForPosition()).GetVectorXY();
+
+    result = screenPositionTopLeft + anchorPointOffSet;
+  }
+  return result;
+}
+
+const Vector2 CalculateCurrentActorScreenPosition(const Actor& actor, BufferIndex bufferIndex)
+{
+  Vector2 result;
+  if(actor.OnScene())
+  {
+    Vector3 worldPosition = CalculateCurrentWorldPosition(actor, bufferIndex);
+    Vector3 actorSize     = CalculateCurrentScaledActorSize(actor, bufferIndex);
+
+    auto sceneSize = actor.GetScene().GetCurrentSurfaceRect(); // Use the update object's size
+
+    Vector2 screenPositionTopLeft = CalculateActorTopLeftScreenPosition(sceneSize, actorSize, worldPosition);
+    Vector2 anchorPointOffSet     = (actorSize * actor.GetAnchorPointForPosition()).GetVectorXY();
+
+    result = screenPositionTopLeft + anchorPointOffSet;
+  }
+  return result;
+}
+
+Rect<> CalculateActorScreenExtents(const Actor& actor)
+{
+  Vector2 position2;
+  Vector2 size2;
+  if(actor.OnScene())
+  {
+    Matrix worldTransformMatrix(false); // Do not initialize. It will be calculated in RetrieveCalculatedWorldPosition API.
+
+    Vector3 worldPosition = RetrieveCalculatedWorldPosition(actor, worldTransformMatrix);
+    Vector3 actorSize     = CalculateScaledActorSize(actor, worldTransformMatrix);
+
+    auto sceneSize = actor.GetScene().GetSize();
+
+    position2 = CalculateActorTopLeftScreenPosition(sceneSize, actorSize, worldPosition);
+    size2     = Vector2(actorSize.width, actorSize.height);
+  }
+  return {position2.x, position2.y, size2.x, size2.y};
+}
+
+Rect<> CalculateCurrentActorScreenExtents(const Actor& actor, BufferIndex bufferIndex)
+{
+  Vector2 position2;
+  Vector2 size2;
+  if(actor.OnScene())
+  {
+    Vector3 worldPosition = CalculateCurrentWorldPosition(actor, bufferIndex);
+    Vector3 actorSize     = CalculateCurrentScaledActorSize(actor, bufferIndex);
+
+    auto sceneSize = actor.GetScene().GetCurrentSurfaceRect(); // Use the update object's size
+
+    position2 = CalculateActorTopLeftScreenPosition(sceneSize, actorSize, worldPosition);
+    size2     = Vector2(actorSize.width, actorSize.height);
+  }
+  return {position2.x, position2.y, size2.x, size2.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(!GetViewportExtentsFromRenderTask(renderTask, viewportExtent))
+    {
+      return success;
+    }
+
+    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)
+{
+  Vector2 result;
+  if(actor.OnScene())
+  {
+    auto worldMatrix = Dali::Internal::CalculateActorWorldTransform(actor);
+    const auto& renderTaskList = actor.GetScene().GetRenderTaskList();
+
+    ConvertLocalToScreenRenderTaskList(renderTaskList, actor, worldMatrix, actor.GetTargetSize() * (actor.GetAnchorPointForPosition() - Vector3(0.5f, 0.5f, 0.5f)), result.x, result.y);
+  }
+  return result;
+}
+
+const Vector2 CalculateCurrentActorScreenPositionRenderTaskList(const Actor& actor, BufferIndex bufferIndex)
+{
+  Vector2 result;
   if(actor.OnScene())
   {
-    const auto& node           = actor.GetNode();
-    Vector3     worldPosition  = node.GetWorldPosition(bufferIndex);
-    Vector3     cameraPosition = scene.GetDefaultCameraActor().GetNode().GetWorldPosition(bufferIndex);
-    worldPosition -= cameraPosition;
+    const auto& node = actor.GetNode();
+    const auto& worldMatrix = node.GetWorldMatrix(bufferIndex);
+    const auto& renderTaskList = actor.GetScene().GetRenderTaskList();
+
+    ConvertLocalToScreenRenderTaskList(renderTaskList, actor, worldMatrix, node.GetSize(bufferIndex) * (actor.GetAnchorPointForPosition() - Vector3(0.5f, 0.5f, 0.5f)), result.x, result.y);
+  }
+  return result;
+}
+
+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(!GetViewportExtentsFromRenderTask(renderTask, viewportExtent))
+    {
+      return success;
+    }
+
+    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 = 0.0f;
+    float minScreenY = 0.0f;
+    float maxScreenX = 0.0f;
+    float maxScreenY = 0.0f;
+
+    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       = 0.0f;
+        float   screenY       = 0.0f;
+        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;
+}
 
-    Vector3 actorSize = node.GetSize(bufferIndex) * node.GetWorldScale(bufferIndex);
-    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();
-    return Vector2(halfSceneSize.width + worldPosition.x - anchorPointOffSet.x,
-                   halfSceneSize.height + worldPosition.y - anchorPointOffSet.y);
+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 Vector2::ZERO;
+  return false;
 }
 
-Rect<> CalculateActorScreenExtents(const Actor& actor, const Vector2& screenPosition, BufferIndex bufferIndex)
+Rect<> CalculateActorScreenExtentsRenderTaskList(const Actor& actor)
 {
-  const auto& node              = actor.GetNode();
-  Vector3     size              = node.GetSize(bufferIndex) * node.GetWorldScale(bufferIndex);
-  Vector3     anchorPointOffSet = size * actor.GetAnchorPointForPosition();
-  Vector2     position          = Vector2(screenPosition.x - anchorPointOffSet.x, screenPosition.y - anchorPointOffSet.y);
-  return {position.x, position.y, size.x, size.y};
+  Rect<> result = {0.0f, 0.0f, 0.0f, 0.0f};
+
+  if(actor.OnScene())
+  {
+    Scene& scene = actor.GetScene();
+
+    auto        worldMatrix    = Dali::Internal::CalculateActorWorldTransform(actor);
+    const auto& renderTaskList = scene.GetRenderTaskList();
+    ConvertLocalToScreenExtentRenderTaskList(renderTaskList, actor, worldMatrix, actor.GetTargetSize(), result);
+  }
+  return result;
+}
+
+Rect<> CalculateCurrentActorScreenExtentsRenderTaskList(const Actor& actor, BufferIndex bufferIndex)
+{
+  Rect<> result = {0.0f, 0.0f, 0.0f, 0.0f};
+
+  if(actor.OnScene())
+  {
+    const auto& node = actor.GetNode();
+    const auto& worldMatrix = node.GetWorldMatrix(bufferIndex);
+    const auto& renderTaskList = actor.GetScene().GetRenderTaskList();
+
+    ConvertLocalToScreenExtentRenderTaskList(renderTaskList, actor, worldMatrix, node.GetSize(bufferIndex), result);
+  }
+  return result;
+}
+
+/**
+ * @brief Computes and center position by using transform properties.
+ * @param[in] anchorPoint anchorPoint of an actor.
+ * @param[in] positionUsesAnchorPoint positionUsesAnchorPoint of an actor.
+ * @param[in] size size of an actor.
+ * @param[in] scale scale of an actor.
+ * @param[in] orientation orientation of an actor.
+ */
+Vector3 CalculateCenterPosition(
+  const Vector3&    anchorPoint,
+  const bool        positionUsesAnchorPoint,
+  const Vector3&    size,
+  const Vector3&    scale,
+  const Quaternion& orientation)
+{
+  Vector3       centerPosition;
+  const Vector3 half(0.5f, 0.5f, 0.5f);
+  const Vector3 topLeft(0.0f, 0.0f, 0.5f);
+  // Calculate the center-point by applying the scale and rotation on the anchor point.
+  centerPosition = (half - anchorPoint) * size * scale;
+  centerPosition *= orientation;
+
+  // If the position is ignoring the anchor-point, then remove the anchor-point shift from the position.
+  if(!positionUsesAnchorPoint)
+  {
+    centerPosition -= (topLeft - anchorPoint) * size;
+  }
+  return centerPosition;
+}
+
+Matrix CalculateActorWorldTransform(const Actor& actor)
+{
+  enum InheritanceMode
+  {
+    DONT_INHERIT_TRANSFORM = 0,
+    INHERIT_POSITION       = 1,
+    INHERIT_SCALE          = 2,
+    INHERIT_ORIENTATION    = 4,
+    INHERIT_ALL            = INHERIT_POSITION | INHERIT_SCALE | INHERIT_ORIENTATION,
+  };
+
+  std::vector<Dali::Actor>     descentList;
+  std::vector<InheritanceMode> inheritanceModeList;
+  Dali::Actor                  currentActor(const_cast<Actor*>(&actor));
+  int                          inheritance = 0;
+  do
+  {
+    inheritance = (static_cast<int>(currentActor.GetProperty<bool>(Dali::Actor::Property::INHERIT_ORIENTATION)) << 2) +
+                  (static_cast<int>(currentActor.GetProperty<bool>(Dali::Actor::Property::INHERIT_SCALE)) << 1) +
+                  static_cast<int>(currentActor.GetProperty<bool>(Dali::Actor::Property::INHERIT_POSITION));
+    inheritanceModeList.push_back(static_cast<InheritanceMode>(inheritance));
+    descentList.push_back(currentActor);
+    currentActor = currentActor.GetParent();
+  } while(inheritance != DONT_INHERIT_TRANSFORM && currentActor);
+
+  Matrix  worldMatrix;
+  Vector3 localPosition;
+
+  // descentList is leaf first, so traverse from root (end) to leaf (beginning)
+  const size_t descentCount = descentList.size();
+  for(size_t iter = 0u; iter < descentCount; ++iter)
+  {
+    auto       i                       = descentCount - iter - 1u;
+    Vector3    anchorPoint             = descentList[i].GetProperty<Vector3>(Dali::Actor::Property::ANCHOR_POINT);
+    Vector3    parentOrigin            = descentList[i].GetProperty<Vector3>(Dali::Actor::Property::PARENT_ORIGIN);
+    bool       positionUsesAnchorPoint = descentList[i].GetProperty<bool>(Dali::Actor::Property::POSITION_USES_ANCHOR_POINT);
+    Vector3    size                    = descentList[i].GetProperty<Vector3>(Dali::Actor::Property::SIZE);
+    Vector3    actorPosition           = descentList[i].GetProperty<Vector3>(Dali::Actor::Property::POSITION);
+    Quaternion localOrientation        = descentList[i].GetProperty<Quaternion>(Dali::Actor::Property::ORIENTATION);
+    Vector3    localScale              = descentList[i].GetProperty<Vector3>(Dali::Actor::Property::SCALE);
+
+    Vector3 centerPosition = CalculateCenterPosition(anchorPoint, positionUsesAnchorPoint, size, localScale, localOrientation);
+    if(inheritanceModeList[i] != DONT_INHERIT_TRANSFORM && descentList[i].GetParent())
+    {
+      Matrix  localMatrix;
+      Vector3 parentSize = descentList[i + 1].GetProperty<Vector3>(Dali::Actor::Property::SIZE);
+      if(inheritanceModeList[i] == INHERIT_ALL)
+      {
+        localPosition = actorPosition + centerPosition + (parentOrigin - Vector3(0.5f, 0.5f, 0.5f)) * parentSize;
+        localMatrix.SetTransformComponents(localScale, localOrientation, localPosition);
+
+        //Update the world matrix
+        Matrix tempMatrix;
+        MatrixUtils::MultiplyTransformMatrix(tempMatrix, localMatrix, worldMatrix);
+        worldMatrix = tempMatrix;
+      }
+      else
+      {
+        // Get Parent information.
+        Vector3       parentPosition, parentScale;
+        Quaternion    parentOrientation;
+        const Matrix& parentMatrix = worldMatrix;
+        parentMatrix.GetTransformComponents(parentPosition, parentOrientation, parentScale);
+
+        // Compute intermediate Local information
+        centerPosition                    = CalculateCenterPosition(anchorPoint, positionUsesAnchorPoint, size, localScale, localOrientation);
+        Vector3 intermediateLocalPosition = actorPosition + centerPosition + (parentOrigin - Vector3(0.5f, 0.5f, 0.5f)) * parentSize;
+        Matrix  intermediateLocalMatrix;
+        intermediateLocalMatrix.SetTransformComponents(localScale, localOrientation, intermediateLocalPosition);
+
+        // Compute intermediate world information
+        Matrix intermediateWorldMatrix;
+        MatrixUtils::MultiplyTransformMatrix(intermediateWorldMatrix, intermediateLocalMatrix, parentMatrix);
+
+        Vector3    intermediateWorldPosition, intermediateWorldScale;
+        Quaternion intermediateWorldOrientation;
+        intermediateWorldMatrix.GetTransformComponents(intermediateWorldPosition, intermediateWorldOrientation, intermediateWorldScale);
+
+        // Compute final world information
+        Vector3    finalWorldPosition    = intermediateWorldPosition;
+        Vector3    finalWorldScale       = intermediateWorldScale;
+        Quaternion finalWorldOrientation = intermediateWorldOrientation;
+        // worldScale includes the influence of local scale, local rotation, and parent scale.
+        // So, for the final world matrix, if this node inherits its parent scale, use worldScale.
+        // If not, use local scale for the final world matrix.
+        if((inheritanceModeList[i] & INHERIT_SCALE) == 0)
+        {
+          finalWorldScale = localScale;
+        }
+
+        // For the final world matrix, if this node inherits its parent orientation, use worldOrientation.
+        // If not, use local orientation for the final world matrix.
+        if((inheritanceModeList[i] & INHERIT_ORIENTATION) == 0)
+        {
+          finalWorldOrientation = localOrientation;
+        }
+
+        // The final world position of this node is computed as a sum of
+        // parent origin position in world space and relative position of center from parent origin.
+        // If this node doesn't inherit its parent position, simply use the relative position as a final world position.
+        Vector3 localCenterPosition = CalculateCenterPosition(anchorPoint, positionUsesAnchorPoint, size, finalWorldScale, finalWorldOrientation);
+        finalWorldPosition          = actorPosition * finalWorldScale;
+        finalWorldPosition *= finalWorldOrientation;
+        finalWorldPosition += localCenterPosition;
+        if((inheritanceModeList[i] & INHERIT_POSITION) != 0)
+        {
+          Vector4 parentOriginPosition((parentOrigin - Vector3(0.5f, 0.5f, 0.5f)) * parentSize);
+          parentOriginPosition.w = 1.0f;
+          finalWorldPosition += Vector3(parentMatrix * parentOriginPosition);
+        }
+
+        worldMatrix.SetTransformComponents(finalWorldScale, finalWorldOrientation, finalWorldPosition);
+      }
+    }
+    else
+    {
+      localPosition = actorPosition + centerPosition;
+      worldMatrix.SetTransformComponents(localScale, localOrientation, localPosition);
+    }
+  }
+
+  return worldMatrix;
+}
+
+Vector4 CalculateActorWorldColor(const Actor& actor)
+{
+  std::vector<Dali::Actor>     descentList;
+  std::vector<Dali::ColorMode> inheritanceModeList;
+  Dali::Actor                  currentActor(const_cast<Actor*>(&actor));
+  Dali::ColorMode              inheritance = Dali::ColorMode::USE_OWN_MULTIPLY_PARENT_ALPHA;
+  do
+  {
+    inheritance = currentActor.GetProperty<Dali::ColorMode>(Dali::Actor::Property::COLOR_MODE);
+    inheritanceModeList.push_back(inheritance);
+    descentList.push_back(currentActor);
+    currentActor = currentActor.GetParent();
+  } while(inheritance != Dali::ColorMode::USE_OWN_COLOR && currentActor);
+
+  Vector4      worldColor;
+  const size_t descentCount = descentList.size();
+  for(size_t iter = 0u; iter < descentCount; ++iter)
+  {
+    auto i = descentCount - iter - 1u;
+    if(inheritanceModeList[i] == USE_OWN_COLOR || i == descentList.size() - 1)
+    {
+      worldColor = descentList[i].GetProperty<Vector4>(Dali::Actor::Property::COLOR);
+    }
+    else if(inheritanceModeList[i] == USE_OWN_MULTIPLY_PARENT_ALPHA)
+    {
+      Vector4 ownColor = descentList[i].GetProperty<Vector4>(Dali::Actor::Property::COLOR);
+      worldColor       = Vector4(ownColor.r, ownColor.g, ownColor.b, ownColor.a * worldColor.a);
+    }
+    else if(inheritanceModeList[i] == USE_OWN_MULTIPLY_PARENT_COLOR)
+    {
+      Vector4 ownColor = descentList[i].GetProperty<Vector4>(Dali::Actor::Property::COLOR);
+      worldColor *= ownColor;
+    }
+  }
+
+  return worldColor;
+}
+
+Quaternion CalculateActorLookAtOrientation(const Actor& actor, Vector3 target, Vector3 up, Vector3 localForward, Vector3 localUp)
+{
+  Vector3 currentWorldPosition = Dali::Internal::CalculateActorWorldTransform(actor).GetTranslation3();
+
+  Quaternion worldToTarget = GetOrientationFromForwardAndUpVector(target - currentWorldPosition, up);
+  Quaternion worldToLocal  = GetOrientationFromForwardAndUpVector(localForward, localUp);
+
+  // Rotate by this order : Local --> World --> Target
+  Quaternion ret = worldToTarget / worldToLocal;
+
+  // If we inherit orientation, get parent's world orientation, and revert it.
+  if(actor.IsOrientationInherited() && actor.GetParent())
+  {
+    // Get Parent information.
+    Vector3       parentPosition, parentScale;
+    Quaternion    parentOrientation;
+    const Matrix& parentMatrix = Dali::Internal::CalculateActorWorldTransform(*actor.GetParent());
+    parentMatrix.GetTransformComponents(parentPosition, parentOrientation, parentScale);
+
+    ret = ret / parentOrientation;
+  }
+
+  return ret;
 }
 
 } // namespace Dali::Internal