+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, 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(!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;
+}
+
+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;
+}
+