2 * Copyright (c) 2022 Samsung Electronics Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 #include <dali/internal/common/matrix-utils.h>
18 #include <dali/internal/event/actors/actor-coords.h>
19 #include <dali/internal/event/common/event-thread-services.h>
20 #include <dali/internal/event/common/projection.h>
21 #include <dali/internal/event/common/scene-impl.h>
22 #include <dali/internal/update/nodes/node.h>
24 namespace Dali::Internal
29 * @brief Get the Viewport Extents from RenderTask
31 * @param[in] renderTask RenderTask what we want to get viewport.
32 * @param[out] viewportExtent Calculated extent by renderTask.
33 * @return True if we success to get viewports. False otherwise
35 bool GetViewportExtentsFromRenderTask(const RenderTask& renderTask, Rect<float>& viewportExtent)
37 if(renderTask.GetFrameBuffer())
39 Dali::Actor mappingActor = renderTask.GetScreenToFrameBufferMappingActor();
42 // NOTE : We will assume that mapping actor always use default camera.
43 Vector2 screenPosition = mappingActor.GetProperty<Vector2>(Dali::Actor::Property::SCREEN_POSITION);
44 Vector3 size = mappingActor.GetCurrentProperty<Vector3>(Dali::Actor::Property::SIZE) * mappingActor.GetCurrentProperty<Vector3>(Dali::Actor::Property::WORLD_SCALE);
45 Vector3 anchorPointOffSet = size * GetImplementation(mappingActor).GetAnchorPointForPosition();
46 Vector2 position = Vector2(screenPosition.x - anchorPointOffSet.x, screenPosition.y - anchorPointOffSet.y);
47 viewportExtent.x = position.x;
48 viewportExtent.y = position.y;
49 viewportExtent.width = size.x;
50 viewportExtent.height = size.y;
60 renderTask.GetViewport(viewport);
61 viewportExtent.x = viewport.x;
62 viewportExtent.y = viewport.y;
63 viewportExtent.width = viewport.width;
64 viewportExtent.height = viewport.height;
69 bool ConvertScreenToLocal(
70 const Matrix& viewMatrix,
71 const Matrix& projectionMatrix,
72 const Matrix& worldMatrix,
73 const Vector3& currentSize,
74 const Viewport& viewport,
80 // Get the ModelView matrix
82 MatrixUtils::Multiply(modelView, worldMatrix, viewMatrix);
84 // Calculate the inverted ModelViewProjection matrix; this will be used for 2 unprojects
85 Matrix invertedMvp(false /*don't init*/);
86 MatrixUtils::Multiply(invertedMvp, modelView, projectionMatrix);
87 bool success = invertedMvp.Invert();
89 // Convert to GL coordinates
90 Vector4 screenPos(screenX - static_cast<float>(viewport.x), static_cast<float>(viewport.height) - screenY - static_cast<float>(viewport.y), 0.f, 1.f);
95 success = Unproject(screenPos, invertedMvp, static_cast<float>(viewport.width), static_cast<float>(viewport.height), nearPos);
102 success = Unproject(screenPos, invertedMvp, static_cast<float>(viewport.width), static_cast<float>(viewport.height), farPos);
108 if(XyPlaneIntersect(nearPos, farPos, local))
110 Vector3 size = currentSize;
111 localX = local.x + size.x * 0.5f;
112 localY = local.y + size.y * 0.5f;
123 bool ConvertScreenToLocalRenderTask(
124 const RenderTask& renderTask,
125 const Matrix& worldMatrix,
126 const Vector3& currentSize,
132 bool success = false;
133 CameraActor* camera = renderTask.GetCameraActor();
137 renderTask.GetViewport(viewport);
139 // need to translate coordinates to render tasks coordinate space
140 Vector2 converted(screenX, screenY);
141 if(renderTask.TranslateCoordinates(converted))
143 success = ConvertScreenToLocal(camera->GetViewMatrix(), camera->GetProjectionMatrix(), worldMatrix, currentSize, viewport, localX, localY, converted.x, converted.y);
149 bool ConvertScreenToLocalRenderTaskList(
150 const RenderTaskList& renderTaskList,
151 const Matrix& worldMatrix,
152 const Vector3& currentSize,
158 // do a reverse traversal of all lists (as the default onscreen one is typically the last one)
159 uint32_t taskCount = renderTaskList.GetTaskCount();
160 for(uint32_t i = taskCount; i > 0; --i)
162 RenderTaskPtr task = renderTaskList.GetTask(i - 1);
163 if(ConvertScreenToLocalRenderTask(*task, worldMatrix, currentSize, localX, localY, screenX, screenY))
165 // found a task where this conversion was ok so return
172 const Vector2 CalculateActorScreenPosition(const Actor& actor, BufferIndex bufferIndex)
174 Scene& scene = actor.GetScene();
177 const auto& node = actor.GetNode();
178 Vector3 worldPosition = node.GetWorldPosition(bufferIndex);
179 Vector3 cameraPosition = scene.GetDefaultCameraActor().GetNode().GetWorldPosition(bufferIndex);
180 worldPosition -= cameraPosition;
182 Vector3 actorSize = node.GetSize(bufferIndex) * node.GetWorldScale(bufferIndex);
183 auto sceneSize = scene.GetCurrentSurfaceRect(); // Use the update object's size
184 Vector2 halfSceneSize(sceneSize.width * 0.5f, sceneSize.height * 0.5f); // World position origin is center of scene
185 Vector3 halfActorSize(actorSize * 0.5f);
186 Vector3 anchorPointOffSet = halfActorSize - actorSize * actor.GetAnchorPointForPosition();
187 return Vector2(halfSceneSize.width + worldPosition.x - anchorPointOffSet.x,
188 halfSceneSize.height + worldPosition.y - anchorPointOffSet.y);
190 return Vector2::ZERO;
193 Rect<> CalculateActorScreenExtents(const Actor& actor, const Vector2& screenPosition, BufferIndex bufferIndex)
195 const auto& node = actor.GetNode();
196 Vector3 size = node.GetSize(bufferIndex) * node.GetWorldScale(bufferIndex);
197 Vector3 anchorPointOffSet = size * actor.GetAnchorPointForPosition();
198 Vector2 position = Vector2(screenPosition.x - anchorPointOffSet.x, screenPosition.y - anchorPointOffSet.y);
199 return {position.x, position.y, size.x, size.y};
202 bool ConvertLocalToScreen(
203 const Matrix& viewMatrix,
204 const Matrix& projectionMatrix,
205 const Matrix& worldMatrix,
206 const Rect<>& viewportExtent,
207 const Vector3& localPosition,
211 bool success = false;
213 // Convert local to projection coordinates
214 // note, P*(V*(M*pos))) is faster than (P*V*M)*pos
215 Vector4 mvpPos(localPosition.x, localPosition.y, localPosition.z, 1.0f);
217 mvpPos = worldMatrix * mvpPos;
218 mvpPos = viewMatrix * mvpPos;
219 mvpPos = projectionMatrix * mvpPos;
221 if(DALI_LIKELY(!EqualsZero(mvpPos.w)))
224 screenX = viewportExtent.x + (mvpPos.x + mvpPos.w) * viewportExtent.width * 0.5f / mvpPos.w;
225 screenY = viewportExtent.y + (-mvpPos.y + mvpPos.w) * viewportExtent.height * 0.5f / mvpPos.w;
230 bool ConvertLocalToScreenRenderTask(
231 const RenderTask& renderTask,
233 const Matrix& worldMatrix,
234 const Vector3& localPosition,
238 bool success = false;
239 const Actor* sourceActor = renderTask.GetSourceActor();
240 if(sourceActor == nullptr)
245 // Check whether current actor is in this rendertask.
246 bool actorInRendertask = false;
247 const Actor* targetActor = &actor;
250 if(sourceActor == targetActor)
252 actorInRendertask = true;
255 targetActor = targetActor->GetParent();
257 if(!actorInRendertask)
262 CameraActor* camera = renderTask.GetCameraActor();
265 Rect<float> viewportExtent = {0.f, 0.f, 0.f, 0.f};
266 if(!GetViewportExtentsFromRenderTask(renderTask, viewportExtent))
271 if(ConvertLocalToScreen(camera->GetViewMatrix(), camera->GetProjectionMatrix(), worldMatrix, viewportExtent, localPosition, screenX, screenY))
279 bool ConvertLocalToScreenRenderTaskList(
280 const RenderTaskList& renderTaskList,
282 const Matrix& worldMatrix,
283 const Vector3& localPosition,
287 // do a reverse traversal of all lists (as the default onscreen one is typically the last one)
288 uint32_t taskCount = renderTaskList.GetTaskCount();
289 for(uint32_t i = taskCount; i > 0; --i)
291 RenderTaskPtr task = renderTaskList.GetTask(i - 1);
292 if(ConvertLocalToScreenRenderTask(*task, actor, worldMatrix, localPosition, screenX, screenY))
294 // found a task where this conversion was ok so return
301 const Vector2 CalculateActorScreenPositionRenderTaskList(const Actor& actor, BufferIndex bufferIndex)
305 const auto& node = actor.GetNode();
306 Scene& scene = actor.GetScene();
310 auto worldMatrix = node.GetWorldMatrix(bufferIndex);
311 const auto& renderTaskList = scene.GetRenderTaskList();
312 ConvertLocalToScreenRenderTaskList(renderTaskList, actor, worldMatrix, node.GetSize(bufferIndex) * (actor.GetAnchorPointForPosition() - Vector3(0.5f, 0.5f, 0.5f)), result.x, result.y);
316 return Vector2::ZERO;
319 bool ConvertLocalToScreenExtentRenderTask(
320 const RenderTask& renderTask,
322 const Matrix& worldMatrix,
323 const Vector3& currentSize,
324 Rect<>& screenExtent)
326 bool success = false;
327 const Actor* sourceActor = renderTask.GetSourceActor();
328 if(sourceActor == nullptr)
333 // Check whether current actor is in this rendertask.
334 bool actorInRendertask = false;
335 const Actor* targetActor = &actor;
338 if(sourceActor == targetActor)
340 actorInRendertask = true;
343 targetActor = targetActor->GetParent();
345 if(!actorInRendertask)
350 CameraActor* camera = renderTask.GetCameraActor();
353 Rect<float> viewportExtent = {0.f, 0.f, 0.f, 0.f};
354 if(!GetViewportExtentsFromRenderTask(renderTask, viewportExtent))
359 constexpr uint32_t BOX_POINT_COUNT = 8;
360 const Vector3 BBOffset[BOX_POINT_COUNT] = {
361 Vector3(-currentSize.width * 0.5f, -currentSize.height * 0.5f, -currentSize.depth * 0.5f),
362 Vector3(-currentSize.width * 0.5f, currentSize.height * 0.5f, -currentSize.depth * 0.5f),
363 Vector3(currentSize.width * 0.5f, -currentSize.height * 0.5f, -currentSize.depth * 0.5f),
364 Vector3(currentSize.width * 0.5f, currentSize.height * 0.5f, -currentSize.depth * 0.5f),
365 Vector3(-currentSize.width * 0.5f, -currentSize.height * 0.5f, currentSize.depth * 0.5f),
366 Vector3(-currentSize.width * 0.5f, currentSize.height * 0.5f, currentSize.depth * 0.5f),
367 Vector3(currentSize.width * 0.5f, -currentSize.height * 0.5f, currentSize.depth * 0.5f),
368 Vector3(currentSize.width * 0.5f, currentSize.height * 0.5f, currentSize.depth * 0.5f),
371 float minScreenX = 0.0f;
372 float minScreenY = 0.0f;
373 float maxScreenX = 0.0f;
374 float maxScreenY = 0.0f;
376 const auto& viewMatrix = camera->GetViewMatrix();
377 const auto& projectionMatrix = camera->GetProjectionMatrix();
379 success = ConvertLocalToScreen(viewMatrix, projectionMatrix, worldMatrix, viewportExtent, BBOffset[0], minScreenX, minScreenY);
382 maxScreenX = minScreenX;
383 maxScreenY = minScreenY;
384 for(uint32_t i = 1; i < BOX_POINT_COUNT; ++i)
386 float screenX = 0.0f;
387 float screenY = 0.0f;
388 Vector3 localPosition = BBOffset[i];
389 if(DALI_UNLIKELY(!ConvertLocalToScreen(viewMatrix, projectionMatrix, worldMatrix, viewportExtent, localPosition, screenX, screenY)))
394 minScreenX = std::min(minScreenX, screenX);
395 maxScreenX = std::max(maxScreenX, screenX);
396 minScreenY = std::min(minScreenY, screenY);
397 maxScreenY = std::max(maxScreenY, screenY);
401 screenExtent.x = minScreenX;
402 screenExtent.y = minScreenY;
403 screenExtent.width = maxScreenX - minScreenX;
404 screenExtent.height = maxScreenY - minScreenY;
411 bool ConvertLocalToScreenExtentRenderTaskList(
412 const RenderTaskList& renderTaskList,
414 const Matrix& worldMatrix,
415 const Vector3& currentSize,
416 Rect<>& screenExtent)
418 // do a reverse traversal of all lists (as the default onscreen one is typically the last one)
419 uint32_t taskCount = renderTaskList.GetTaskCount();
420 for(uint32_t i = taskCount; i > 0; --i)
422 RenderTaskPtr task = renderTaskList.GetTask(i - 1);
423 if(ConvertLocalToScreenExtentRenderTask(*task, actor, worldMatrix, currentSize, screenExtent))
425 // found a task where this conversion was ok so return
432 Rect<> CalculateActorScreenExtentsRenderTaskList(const Actor& actor, BufferIndex bufferIndex)
434 Rect<> result = {0.0f, 0.0f, 0.0f, 0.0f};
438 const auto& node = actor.GetNode();
439 Scene& scene = actor.GetScene();
441 auto worldMatrix = node.GetWorldMatrix(bufferIndex);
442 const auto& renderTaskList = scene.GetRenderTaskList();
443 ConvertLocalToScreenExtentRenderTaskList(renderTaskList, actor, worldMatrix, node.GetSize(bufferIndex), result);
449 * @brief Computes and center position by using transform properties.
450 * @param[in] anchorPoint anchorPoint of an actor.
451 * @param[in] positionUsesAnchorPoint positionUsesAnchorPoint of an actor.
452 * @param[in] size size of an actor.
453 * @param[in] scale scale of an actor.
454 * @param[in] orientation orientation of an actor.
456 Vector3 CalculateCenterPosition(
457 const Vector3& anchorPoint,
458 const bool positionUsesAnchorPoint,
460 const Vector3& scale,
461 const Quaternion& orientation)
463 Vector3 centerPosition;
464 const Vector3 half(0.5f, 0.5f, 0.5f);
465 const Vector3 topLeft(0.0f, 0.0f, 0.5f);
466 // Calculate the center-point by applying the scale and rotation on the anchor point.
467 centerPosition = (half - anchorPoint) * size * scale;
468 centerPosition *= orientation;
470 // If the position is ignoring the anchor-point, then remove the anchor-point shift from the position.
471 if(!positionUsesAnchorPoint)
473 centerPosition -= (topLeft - anchorPoint) * size;
475 return centerPosition;
478 Matrix CalculateActorWorldTransform(const Actor& actor)
482 DONT_INHERIT_TRANSFORM = 0,
483 INHERIT_POSITION = 1,
485 INHERIT_ORIENTATION = 4,
486 INHERIT_ALL = INHERIT_POSITION | INHERIT_SCALE | INHERIT_ORIENTATION,
489 std::vector<Dali::Actor> descentList;
490 std::vector<InheritanceMode> inheritanceModeList;
491 Dali::Actor currentActor(const_cast<Actor*>(&actor));
495 inheritance = (static_cast<int>(currentActor.GetProperty<bool>(Dali::Actor::Property::INHERIT_ORIENTATION)) << 2) +
496 (static_cast<int>(currentActor.GetProperty<bool>(Dali::Actor::Property::INHERIT_SCALE)) << 1) +
497 static_cast<int>(currentActor.GetProperty<bool>(Dali::Actor::Property::INHERIT_POSITION));
498 inheritanceModeList.push_back(static_cast<InheritanceMode>(inheritance));
499 descentList.push_back(currentActor);
500 currentActor = currentActor.GetParent();
501 } while(inheritance != DONT_INHERIT_TRANSFORM && currentActor);
504 Vector3 localPosition;
506 // descentList is leaf first, so traverse from root (end) to leaf (beginning)
507 const size_t descentCount = descentList.size();
508 for(size_t iter = 0u; iter < descentCount; ++iter)
510 auto i = descentCount - iter - 1u;
511 Vector3 anchorPoint = descentList[i].GetProperty<Vector3>(Dali::Actor::Property::ANCHOR_POINT);
512 Vector3 parentOrigin = descentList[i].GetProperty<Vector3>(Dali::Actor::Property::PARENT_ORIGIN);
513 bool positionUsesAnchorPoint = descentList[i].GetProperty<bool>(Dali::Actor::Property::POSITION_USES_ANCHOR_POINT);
514 Vector3 size = descentList[i].GetProperty<Vector3>(Dali::Actor::Property::SIZE);
515 Vector3 actorPosition = descentList[i].GetProperty<Vector3>(Dali::Actor::Property::POSITION);
516 Quaternion localOrientation = descentList[i].GetProperty<Quaternion>(Dali::Actor::Property::ORIENTATION);
517 Vector3 localScale = descentList[i].GetProperty<Vector3>(Dali::Actor::Property::SCALE);
519 Vector3 centerPosition = CalculateCenterPosition(anchorPoint, positionUsesAnchorPoint, size, localScale, localOrientation);
520 if(inheritanceModeList[i] != DONT_INHERIT_TRANSFORM && descentList[i].GetParent())
523 Vector3 parentSize = descentList[i + 1].GetProperty<Vector3>(Dali::Actor::Property::SIZE);
524 if(inheritanceModeList[i] == INHERIT_ALL)
526 localPosition = actorPosition + centerPosition + (parentOrigin - Vector3(0.5f, 0.5f, 0.5f)) * parentSize;
527 localMatrix.SetTransformComponents(localScale, localOrientation, localPosition);
529 //Update the world matrix
531 MatrixUtils::Multiply(tempMatrix, localMatrix, worldMatrix);
532 worldMatrix = tempMatrix;
536 Vector3 parentPosition, parentScale;
537 Quaternion parentOrientation;
538 worldMatrix.GetTransformComponents(parentPosition, parentOrientation, parentScale);
540 if((inheritanceModeList[i] & INHERIT_SCALE) == 0)
542 //Don't inherit scale
543 localScale /= parentScale;
546 if((inheritanceModeList[i] & INHERIT_ORIENTATION) == 0)
548 //Don't inherit orientation
549 parentOrientation.Invert();
550 localOrientation = parentOrientation * localOrientation;
553 if((inheritanceModeList[i] & INHERIT_POSITION) == 0)
555 localMatrix.SetTransformComponents(localScale, localOrientation, Vector3::ZERO);
557 MatrixUtils::Multiply(tempMatrix, localMatrix, worldMatrix);
558 worldMatrix = tempMatrix;
559 worldMatrix.SetTranslation(actorPosition + centerPosition);
563 localPosition = actorPosition + centerPosition + (parentOrigin - Vector3(0.5f, 0.5f, 0.5f)) * parentSize;
564 localMatrix.SetTransformComponents(localScale, localOrientation, localPosition);
566 MatrixUtils::Multiply(tempMatrix, localMatrix, worldMatrix);
567 worldMatrix = tempMatrix;
573 localPosition = actorPosition + centerPosition;
574 worldMatrix.SetTransformComponents(localScale, localOrientation, localPosition);
581 Vector4 CalculateActorWorldColor(const Actor& actor)
583 std::vector<Dali::Actor> descentList;
584 std::vector<Dali::ColorMode> inheritanceModeList;
585 Dali::Actor currentActor(const_cast<Actor*>(&actor));
586 Dali::ColorMode inheritance = Dali::ColorMode::USE_OWN_MULTIPLY_PARENT_ALPHA;
589 inheritance = currentActor.GetProperty<Dali::ColorMode>(Dali::Actor::Property::COLOR_MODE);
590 inheritanceModeList.push_back(inheritance);
591 descentList.push_back(currentActor);
592 currentActor = currentActor.GetParent();
593 } while(inheritance != Dali::ColorMode::USE_OWN_COLOR && currentActor);
596 const size_t descentCount = descentList.size();
597 for(size_t iter = 0u; iter < descentCount; ++iter)
599 auto i = descentCount - iter - 1u;
600 if(inheritanceModeList[i] == USE_OWN_COLOR || i == descentList.size() - 1)
602 worldColor = descentList[i].GetProperty<Vector4>(Dali::Actor::Property::COLOR);
604 else if(inheritanceModeList[i] == USE_OWN_MULTIPLY_PARENT_ALPHA)
606 Vector4 ownColor = descentList[i].GetProperty<Vector4>(Dali::Actor::Property::COLOR);
607 worldColor = Vector4(ownColor.r, ownColor.g, ownColor.b, ownColor.a * worldColor.a);
609 else if(inheritanceModeList[i] == USE_OWN_MULTIPLY_PARENT_COLOR)
611 Vector4 ownColor = descentList[i].GetProperty<Vector4>(Dali::Actor::Property::COLOR);
612 worldColor *= ownColor;
619 } // namespace Dali::Internal