Use update object size in CalculateActorScreenPosition
[platform/core/uifw/dali-core.git] / dali / internal / event / actors / actor-coords.cpp
1 /*
2  * Copyright (c) 2021 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <dali/internal/event/actors/actor-coords.h>
18 #include <dali/internal/event/common/event-thread-services.h>
19 #include <dali/internal/event/common/projection.h>
20 #include <dali/internal/event/common/scene-impl.h>
21 #include <dali/internal/update/nodes/node.h>
22
23 namespace Dali::Internal
24 {
25 bool ConvertScreenToLocal(
26   const Matrix&   viewMatrix,
27   const Matrix&   projectionMatrix,
28   const Matrix&   worldMatrix,
29   const Vector3&  currentSize,
30   const Viewport& viewport,
31   float&          localX,
32   float&          localY,
33   float           screenX,
34   float           screenY)
35 {
36   // Get the ModelView matrix
37   Matrix modelView;
38   Matrix::Multiply(modelView, worldMatrix, viewMatrix);
39
40   // Calculate the inverted ModelViewProjection matrix; this will be used for 2 unprojects
41   Matrix invertedMvp(false /*don't init*/);
42   Matrix::Multiply(invertedMvp, modelView, projectionMatrix);
43   bool success = invertedMvp.Invert();
44
45   // Convert to GL coordinates
46   Vector4 screenPos(screenX - static_cast<float>(viewport.x), static_cast<float>(viewport.height) - screenY - static_cast<float>(viewport.y), 0.f, 1.f);
47
48   Vector4 nearPos;
49   if(success)
50   {
51     success = Unproject(screenPos, invertedMvp, static_cast<float>(viewport.width), static_cast<float>(viewport.height), nearPos);
52   }
53
54   Vector4 farPos;
55   if(success)
56   {
57     screenPos.z = 1.0f;
58     success     = Unproject(screenPos, invertedMvp, static_cast<float>(viewport.width), static_cast<float>(viewport.height), farPos);
59   }
60
61   if(success)
62   {
63     Vector4 local;
64     if(XyPlaneIntersect(nearPos, farPos, local))
65     {
66       Vector3 size = currentSize;
67       localX       = local.x + size.x * 0.5f;
68       localY       = local.y + size.y * 0.5f;
69     }
70     else
71     {
72       success = false;
73     }
74   }
75
76   return success;
77 }
78
79 bool ConvertScreenToLocalRenderTask(
80   const RenderTask& renderTask,
81   const Matrix&     worldMatrix,
82   const Vector3&    currentSize,
83   float&            localX,
84   float&            localY,
85   float             screenX,
86   float             screenY)
87 {
88   bool         success = false;
89   CameraActor* camera  = renderTask.GetCameraActor();
90   if(camera)
91   {
92     Viewport viewport;
93     renderTask.GetViewport(viewport);
94
95     // need to translate coordinates to render tasks coordinate space
96     Vector2 converted(screenX, screenY);
97     if(renderTask.TranslateCoordinates(converted))
98     {
99       success = ConvertScreenToLocal(camera->GetViewMatrix(), camera->GetProjectionMatrix(), worldMatrix, currentSize, viewport, localX, localY, converted.x, converted.y);
100     }
101   }
102   return success;
103 }
104
105 bool ConvertScreenToLocalRenderTaskList(
106   const RenderTaskList& renderTaskList,
107   const Matrix&         worldMatrix,
108   const Vector3&        currentSize,
109   float&                localX,
110   float&                localY,
111   float                 screenX,
112   float                 screenY)
113 {
114   // do a reverse traversal of all lists (as the default onscreen one is typically the last one)
115   uint32_t taskCount = renderTaskList.GetTaskCount();
116   for(uint32_t i = taskCount; i > 0; --i)
117   {
118     RenderTaskPtr task = renderTaskList.GetTask(i - 1);
119     if(ConvertScreenToLocalRenderTask(*task, worldMatrix, currentSize, localX, localY, screenX, screenY))
120     {
121       // found a task where this conversion was ok so return
122       return true;
123     }
124   }
125   return false;
126 };
127
128 const Vector2 CalculateActorScreenPosition(const Actor& actor, BufferIndex bufferIndex)
129 {
130   Scene& scene = actor.GetScene();
131   if(actor.OnScene())
132   {
133     const auto& node           = actor.GetNode();
134     Vector3     worldPosition  = node.GetWorldPosition(bufferIndex);
135     Vector3     cameraPosition = scene.GetDefaultCameraActor().GetNode().GetWorldPosition(bufferIndex);
136     worldPosition -= cameraPosition;
137
138     Vector3 actorSize = node.GetSize(bufferIndex) * node.GetWorldScale(bufferIndex);
139     auto    sceneSize = scene.GetCurrentSurfaceRect();  // Use the update object's size
140     Vector2 halfSceneSize(sceneSize.width * 0.5f, sceneSize.height * 0.5f); // World position origin is center of scene
141     Vector3 halfActorSize(actorSize * 0.5f);
142     Vector3 anchorPointOffSet = halfActorSize - actorSize * actor.GetAnchorPointForPosition();
143     return Vector2(halfSceneSize.width + worldPosition.x - anchorPointOffSet.x,
144                    halfSceneSize.height + worldPosition.y - anchorPointOffSet.y);
145   }
146   return Vector2::ZERO;
147 }
148
149 Rect<> CalculateActorScreenExtents(const Actor& actor, const Vector2& screenPosition, BufferIndex bufferIndex)
150 {
151   const auto& node              = actor.GetNode();
152   Vector3     size              = node.GetSize(bufferIndex) * node.GetWorldScale(bufferIndex);
153   Vector3     anchorPointOffSet = size * actor.GetAnchorPointForPosition();
154   Vector2     position          = Vector2(screenPosition.x - anchorPointOffSet.x, screenPosition.y - anchorPointOffSet.y);
155   return {position.x, position.y, size.x, size.y};
156 }
157
158 } // namespace Dali::Internal