Remove duplicate codes for screen position
[platform/core/uifw/dali-core.git] / dali / internal / event / actors / actor-coords.cpp
index 9fa1983..706a6b9 100644 (file)
@@ -65,7 +65,120 @@ bool GetViewportExtentsFromRenderTask(const RenderTask& renderTask, Rect<float>&
   }
   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,
@@ -79,7 +192,7 @@ bool ConvertScreenToLocal(
 {
   // Get the ModelView matrix
   Matrix modelView;
-  MatrixUtils::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*/);
@@ -167,36 +280,80 @@ 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())
   {
-    const auto& node           = actor.GetNode();
-    Vector3     worldPosition  = node.GetWorldPosition(bufferIndex);
-    Vector3     cameraPosition = scene.GetDefaultCameraActor().GetNode().GetWorldPosition(bufferIndex);
-    worldPosition -= cameraPosition;
-
-    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);
+    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 Vector2::ZERO;
+  return {position2.x, position2.y, size2.x, size2.y};
 }
 
-Rect<> CalculateActorScreenExtents(const Actor& actor, const Vector2& screenPosition, BufferIndex bufferIndex)
+Rect<> CalculateCurrentActorScreenExtents(const Actor& actor, BufferIndex bufferIndex)
 {
-  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};
+  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(
@@ -298,22 +455,31 @@ bool ConvertLocalToScreenRenderTaskList(
   return false;
 }
 
-const Vector2 CalculateActorScreenPositionRenderTaskList(const Actor& actor, BufferIndex bufferIndex)
+const Vector2 CalculateActorScreenPositionRenderTaskList(const Actor& actor)
 {
+  Vector2 result;
   if(actor.OnScene())
   {
-    const auto& node  = actor.GetNode();
-    Scene&      scene = actor.GetScene();
+    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;
+}
 
-    Vector2 result;
+const Vector2 CalculateCurrentActorScreenPositionRenderTaskList(const Actor& actor, BufferIndex bufferIndex)
+{
+  Vector2 result;
+  if(actor.OnScene())
+  {
+    const auto& node = actor.GetNode();
+    const auto& worldMatrix = node.GetWorldMatrix(bufferIndex);
+    const auto& renderTaskList = actor.GetScene().GetRenderTaskList();
 
-    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;
+  return result;
 }
 
 bool ConvertLocalToScreenExtentRenderTask(
@@ -429,17 +595,31 @@ bool ConvertLocalToScreenExtentRenderTaskList(
   return false;
 }
 
-Rect<> CalculateActorScreenExtentsRenderTaskList(const Actor& actor, BufferIndex bufferIndex)
+Rect<> CalculateActorScreenExtentsRenderTaskList(const Actor& actor)
 {
   Rect<> result = {0.0f, 0.0f, 0.0f, 0.0f};
 
   if(actor.OnScene())
   {
-    const auto& node  = actor.GetNode();
-    Scene&      scene = actor.GetScene();
+    Scene& scene = actor.GetScene();
 
-    auto        worldMatrix    = node.GetWorldMatrix(bufferIndex);
+    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;
@@ -528,7 +708,7 @@ Matrix CalculateActorWorldTransform(const Actor& actor)
 
         //Update the world matrix
         Matrix tempMatrix;
-        MatrixUtils::Multiply(tempMatrix, localMatrix, worldMatrix);
+        MatrixUtils::MultiplyTransformMatrix(tempMatrix, localMatrix, worldMatrix);
         worldMatrix = tempMatrix;
       }
       else
@@ -547,7 +727,7 @@ Matrix CalculateActorWorldTransform(const Actor& actor)
 
         // Compute intermediate world information
         Matrix intermediateWorldMatrix;
-        MatrixUtils::Multiply(intermediateWorldMatrix, intermediateLocalMatrix, parentMatrix);
+        MatrixUtils::MultiplyTransformMatrix(intermediateWorldMatrix, intermediateLocalMatrix, parentMatrix);
 
         Vector3    intermediateWorldPosition, intermediateWorldScale;
         Quaternion intermediateWorldOrientation;
@@ -637,4 +817,29 @@ Vector4 CalculateActorWorldColor(const Actor& actor)
   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