2 * Copyright (c) 2023 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;
70 * @brief Get the Orientation from Forward vector and Up vector
71 * If vectors are valid, return Quaternion to make forward direction as +Z, and up direction near as -Y axis.
72 * If some invalid vector inputed (like Zero length, or parallel vector), return identity quaternion
74 * @param[in] forward The vector that want to be +Z axis.
75 * @param[in] up The vector that want to be -Y axis.
76 * @return Quaternion to make forward direction as +Z, and up direction near as -Y axis.
78 Quaternion GetOrientationFromForwardAndUpVector(Vector3 forward, Vector3 up)
83 Vector3 vX = up.Cross(vZ);
86 // If something invalid input comes, vX length become zero.
87 if(DALI_UNLIKELY(Dali::EqualsZero(vX.Length())))
89 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);
93 Vector3 vY = vZ.Cross(vX);
96 return Quaternion(vX, vY, vZ);
99 bool ConvertScreenToLocal(
100 const Matrix& viewMatrix,
101 const Matrix& projectionMatrix,
102 const Matrix& worldMatrix,
103 const Vector3& currentSize,
104 const Viewport& viewport,
110 // Get the ModelView matrix
112 MatrixUtils::MultiplyTransformMatrix(modelView, worldMatrix, viewMatrix);
114 // Calculate the inverted ModelViewProjection matrix; this will be used for 2 unprojects
115 Matrix invertedMvp(false /*don't init*/);
116 MatrixUtils::MultiplyProjectionMatrix(invertedMvp, modelView, projectionMatrix);
117 bool success = invertedMvp.Invert();
119 // Convert to GL coordinates
120 Vector4 screenPos(screenX - static_cast<float>(viewport.x), static_cast<float>(viewport.height) - screenY - static_cast<float>(viewport.y), 0.f, 1.f);
125 success = Unproject(screenPos, invertedMvp, static_cast<float>(viewport.width), static_cast<float>(viewport.height), nearPos);
132 success = Unproject(screenPos, invertedMvp, static_cast<float>(viewport.width), static_cast<float>(viewport.height), farPos);
138 if(XyPlaneIntersect(nearPos, farPos, local))
140 Vector3 size = currentSize;
141 localX = local.x + size.x * 0.5f;
142 localY = local.y + size.y * 0.5f;
153 bool ConvertScreenToLocalRenderTask(
154 const RenderTask& renderTask,
155 const Matrix& worldMatrix,
156 const Vector3& currentSize,
162 bool success = false;
163 CameraActor* camera = renderTask.GetCameraActor();
167 renderTask.GetViewport(viewport);
169 // need to translate coordinates to render tasks coordinate space
170 Vector2 converted(screenX, screenY);
171 if(renderTask.TranslateCoordinates(converted))
173 success = ConvertScreenToLocal(camera->GetViewMatrix(), camera->GetProjectionMatrix(), worldMatrix, currentSize, viewport, localX, localY, converted.x, converted.y);
179 bool ConvertScreenToLocalRenderTaskList(
180 const RenderTaskList& renderTaskList,
181 const Matrix& worldMatrix,
182 const Vector3& currentSize,
188 // do a reverse traversal of all lists (as the default onscreen one is typically the last one)
189 uint32_t taskCount = renderTaskList.GetTaskCount();
190 for(uint32_t i = taskCount; i > 0; --i)
192 RenderTaskPtr task = renderTaskList.GetTask(i - 1);
193 if(ConvertScreenToLocalRenderTask(*task, worldMatrix, currentSize, localX, localY, screenX, screenY))
195 // found a task where this conversion was ok so return
202 const Vector2 CalculateActorScreenPosition(const Actor& actor, BufferIndex bufferIndex)
204 Scene& scene = actor.GetScene();
207 const auto& node = actor.GetNode();
208 Vector3 worldPosition = node.GetWorldPosition(bufferIndex);
209 Vector3 cameraPosition = scene.GetDefaultCameraActor().GetNode().GetWorldPosition(bufferIndex);
210 worldPosition -= cameraPosition;
212 Vector3 actorSize = node.GetSize(bufferIndex) * node.GetWorldScale(bufferIndex);
213 auto sceneSize = scene.GetCurrentSurfaceRect(); // Use the update object's size
214 Vector2 halfSceneSize(sceneSize.width * 0.5f, sceneSize.height * 0.5f); // World position origin is center of scene
215 Vector3 halfActorSize(actorSize * 0.5f);
216 Vector3 anchorPointOffSet = halfActorSize - actorSize * actor.GetAnchorPointForPosition();
217 return Vector2(halfSceneSize.width + worldPosition.x - anchorPointOffSet.x,
218 halfSceneSize.height + worldPosition.y - anchorPointOffSet.y);
220 return Vector2::ZERO;
223 Rect<> CalculateActorScreenExtents(const Actor& actor, const Vector2& screenPosition, BufferIndex bufferIndex)
225 const auto& node = actor.GetNode();
226 Vector3 size = node.GetSize(bufferIndex) * node.GetWorldScale(bufferIndex);
227 Vector3 anchorPointOffSet = size * actor.GetAnchorPointForPosition();
228 Vector2 position = Vector2(screenPosition.x - anchorPointOffSet.x, screenPosition.y - anchorPointOffSet.y);
229 return {position.x, position.y, size.x, size.y};
232 bool ConvertLocalToScreen(
233 const Matrix& viewMatrix,
234 const Matrix& projectionMatrix,
235 const Matrix& worldMatrix,
236 const Rect<>& viewportExtent,
237 const Vector3& localPosition,
241 bool success = false;
243 // Convert local to projection coordinates
244 // note, P*(V*(M*pos))) is faster than (P*V*M)*pos
245 Vector4 mvpPos(localPosition.x, localPosition.y, localPosition.z, 1.0f);
247 mvpPos = worldMatrix * mvpPos;
248 mvpPos = viewMatrix * mvpPos;
249 mvpPos = projectionMatrix * mvpPos;
251 if(DALI_LIKELY(!EqualsZero(mvpPos.w)))
254 screenX = viewportExtent.x + (mvpPos.x + mvpPos.w) * viewportExtent.width * 0.5f / mvpPos.w;
255 screenY = viewportExtent.y + (-mvpPos.y + mvpPos.w) * viewportExtent.height * 0.5f / mvpPos.w;
260 bool ConvertLocalToScreenRenderTask(
261 const RenderTask& renderTask,
263 const Matrix& worldMatrix,
264 const Vector3& localPosition,
268 bool success = false;
269 const Actor* sourceActor = renderTask.GetSourceActor();
270 if(sourceActor == nullptr)
275 // Check whether current actor is in this rendertask.
276 bool actorInRendertask = false;
277 const Actor* targetActor = &actor;
280 if(sourceActor == targetActor)
282 actorInRendertask = true;
285 targetActor = targetActor->GetParent();
287 if(!actorInRendertask)
292 CameraActor* camera = renderTask.GetCameraActor();
295 Rect<float> viewportExtent = {0.f, 0.f, 0.f, 0.f};
296 if(!GetViewportExtentsFromRenderTask(renderTask, viewportExtent))
301 if(ConvertLocalToScreen(camera->GetViewMatrix(), camera->GetProjectionMatrix(), worldMatrix, viewportExtent, localPosition, screenX, screenY))
309 bool ConvertLocalToScreenRenderTaskList(
310 const RenderTaskList& renderTaskList,
312 const Matrix& worldMatrix,
313 const Vector3& localPosition,
317 // do a reverse traversal of all lists (as the default onscreen one is typically the last one)
318 uint32_t taskCount = renderTaskList.GetTaskCount();
319 for(uint32_t i = taskCount; i > 0; --i)
321 RenderTaskPtr task = renderTaskList.GetTask(i - 1);
322 if(ConvertLocalToScreenRenderTask(*task, actor, worldMatrix, localPosition, screenX, screenY))
324 // found a task where this conversion was ok so return
331 const Vector2 CalculateActorScreenPositionRenderTaskList(const Actor& actor, BufferIndex bufferIndex)
335 const auto& node = actor.GetNode();
336 Scene& scene = actor.GetScene();
340 auto worldMatrix = node.GetWorldMatrix(bufferIndex);
341 const auto& renderTaskList = scene.GetRenderTaskList();
342 ConvertLocalToScreenRenderTaskList(renderTaskList, actor, worldMatrix, node.GetSize(bufferIndex) * (actor.GetAnchorPointForPosition() - Vector3(0.5f, 0.5f, 0.5f)), result.x, result.y);
346 return Vector2::ZERO;
349 bool ConvertLocalToScreenExtentRenderTask(
350 const RenderTask& renderTask,
352 const Matrix& worldMatrix,
353 const Vector3& currentSize,
354 Rect<>& screenExtent)
356 bool success = false;
357 const Actor* sourceActor = renderTask.GetSourceActor();
358 if(sourceActor == nullptr)
363 // Check whether current actor is in this rendertask.
364 bool actorInRendertask = false;
365 const Actor* targetActor = &actor;
368 if(sourceActor == targetActor)
370 actorInRendertask = true;
373 targetActor = targetActor->GetParent();
375 if(!actorInRendertask)
380 CameraActor* camera = renderTask.GetCameraActor();
383 Rect<float> viewportExtent = {0.f, 0.f, 0.f, 0.f};
384 if(!GetViewportExtentsFromRenderTask(renderTask, viewportExtent))
389 constexpr uint32_t BOX_POINT_COUNT = 8;
390 const Vector3 BBOffset[BOX_POINT_COUNT] = {
391 Vector3(-currentSize.width * 0.5f, -currentSize.height * 0.5f, -currentSize.depth * 0.5f),
392 Vector3(-currentSize.width * 0.5f, currentSize.height * 0.5f, -currentSize.depth * 0.5f),
393 Vector3(currentSize.width * 0.5f, -currentSize.height * 0.5f, -currentSize.depth * 0.5f),
394 Vector3(currentSize.width * 0.5f, currentSize.height * 0.5f, -currentSize.depth * 0.5f),
395 Vector3(-currentSize.width * 0.5f, -currentSize.height * 0.5f, currentSize.depth * 0.5f),
396 Vector3(-currentSize.width * 0.5f, currentSize.height * 0.5f, currentSize.depth * 0.5f),
397 Vector3(currentSize.width * 0.5f, -currentSize.height * 0.5f, currentSize.depth * 0.5f),
398 Vector3(currentSize.width * 0.5f, currentSize.height * 0.5f, currentSize.depth * 0.5f),
401 float minScreenX = 0.0f;
402 float minScreenY = 0.0f;
403 float maxScreenX = 0.0f;
404 float maxScreenY = 0.0f;
406 const auto& viewMatrix = camera->GetViewMatrix();
407 const auto& projectionMatrix = camera->GetProjectionMatrix();
409 success = ConvertLocalToScreen(viewMatrix, projectionMatrix, worldMatrix, viewportExtent, BBOffset[0], minScreenX, minScreenY);
412 maxScreenX = minScreenX;
413 maxScreenY = minScreenY;
414 for(uint32_t i = 1; i < BOX_POINT_COUNT; ++i)
416 float screenX = 0.0f;
417 float screenY = 0.0f;
418 Vector3 localPosition = BBOffset[i];
419 if(DALI_UNLIKELY(!ConvertLocalToScreen(viewMatrix, projectionMatrix, worldMatrix, viewportExtent, localPosition, screenX, screenY)))
424 minScreenX = std::min(minScreenX, screenX);
425 maxScreenX = std::max(maxScreenX, screenX);
426 minScreenY = std::min(minScreenY, screenY);
427 maxScreenY = std::max(maxScreenY, screenY);
431 screenExtent.x = minScreenX;
432 screenExtent.y = minScreenY;
433 screenExtent.width = maxScreenX - minScreenX;
434 screenExtent.height = maxScreenY - minScreenY;
441 bool ConvertLocalToScreenExtentRenderTaskList(
442 const RenderTaskList& renderTaskList,
444 const Matrix& worldMatrix,
445 const Vector3& currentSize,
446 Rect<>& screenExtent)
448 // do a reverse traversal of all lists (as the default onscreen one is typically the last one)
449 uint32_t taskCount = renderTaskList.GetTaskCount();
450 for(uint32_t i = taskCount; i > 0; --i)
452 RenderTaskPtr task = renderTaskList.GetTask(i - 1);
453 if(ConvertLocalToScreenExtentRenderTask(*task, actor, worldMatrix, currentSize, screenExtent))
455 // found a task where this conversion was ok so return
462 Rect<> CalculateActorScreenExtentsRenderTaskList(const Actor& actor, BufferIndex bufferIndex)
464 Rect<> result = {0.0f, 0.0f, 0.0f, 0.0f};
468 const auto& node = actor.GetNode();
469 Scene& scene = actor.GetScene();
471 auto worldMatrix = node.GetWorldMatrix(bufferIndex);
472 const auto& renderTaskList = scene.GetRenderTaskList();
473 ConvertLocalToScreenExtentRenderTaskList(renderTaskList, actor, worldMatrix, node.GetSize(bufferIndex), result);
479 * @brief Computes and center position by using transform properties.
480 * @param[in] anchorPoint anchorPoint of an actor.
481 * @param[in] positionUsesAnchorPoint positionUsesAnchorPoint of an actor.
482 * @param[in] size size of an actor.
483 * @param[in] scale scale of an actor.
484 * @param[in] orientation orientation of an actor.
486 Vector3 CalculateCenterPosition(
487 const Vector3& anchorPoint,
488 const bool positionUsesAnchorPoint,
490 const Vector3& scale,
491 const Quaternion& orientation)
493 Vector3 centerPosition;
494 const Vector3 half(0.5f, 0.5f, 0.5f);
495 const Vector3 topLeft(0.0f, 0.0f, 0.5f);
496 // Calculate the center-point by applying the scale and rotation on the anchor point.
497 centerPosition = (half - anchorPoint) * size * scale;
498 centerPosition *= orientation;
500 // If the position is ignoring the anchor-point, then remove the anchor-point shift from the position.
501 if(!positionUsesAnchorPoint)
503 centerPosition -= (topLeft - anchorPoint) * size;
505 return centerPosition;
508 Matrix CalculateActorWorldTransform(const Actor& actor)
512 DONT_INHERIT_TRANSFORM = 0,
513 INHERIT_POSITION = 1,
515 INHERIT_ORIENTATION = 4,
516 INHERIT_ALL = INHERIT_POSITION | INHERIT_SCALE | INHERIT_ORIENTATION,
519 std::vector<Dali::Actor> descentList;
520 std::vector<InheritanceMode> inheritanceModeList;
521 Dali::Actor currentActor(const_cast<Actor*>(&actor));
525 inheritance = (static_cast<int>(currentActor.GetProperty<bool>(Dali::Actor::Property::INHERIT_ORIENTATION)) << 2) +
526 (static_cast<int>(currentActor.GetProperty<bool>(Dali::Actor::Property::INHERIT_SCALE)) << 1) +
527 static_cast<int>(currentActor.GetProperty<bool>(Dali::Actor::Property::INHERIT_POSITION));
528 inheritanceModeList.push_back(static_cast<InheritanceMode>(inheritance));
529 descentList.push_back(currentActor);
530 currentActor = currentActor.GetParent();
531 } while(inheritance != DONT_INHERIT_TRANSFORM && currentActor);
534 Vector3 localPosition;
536 // descentList is leaf first, so traverse from root (end) to leaf (beginning)
537 const size_t descentCount = descentList.size();
538 for(size_t iter = 0u; iter < descentCount; ++iter)
540 auto i = descentCount - iter - 1u;
541 Vector3 anchorPoint = descentList[i].GetProperty<Vector3>(Dali::Actor::Property::ANCHOR_POINT);
542 Vector3 parentOrigin = descentList[i].GetProperty<Vector3>(Dali::Actor::Property::PARENT_ORIGIN);
543 bool positionUsesAnchorPoint = descentList[i].GetProperty<bool>(Dali::Actor::Property::POSITION_USES_ANCHOR_POINT);
544 Vector3 size = descentList[i].GetProperty<Vector3>(Dali::Actor::Property::SIZE);
545 Vector3 actorPosition = descentList[i].GetProperty<Vector3>(Dali::Actor::Property::POSITION);
546 Quaternion localOrientation = descentList[i].GetProperty<Quaternion>(Dali::Actor::Property::ORIENTATION);
547 Vector3 localScale = descentList[i].GetProperty<Vector3>(Dali::Actor::Property::SCALE);
549 Vector3 centerPosition = CalculateCenterPosition(anchorPoint, positionUsesAnchorPoint, size, localScale, localOrientation);
550 if(inheritanceModeList[i] != DONT_INHERIT_TRANSFORM && descentList[i].GetParent())
553 Vector3 parentSize = descentList[i + 1].GetProperty<Vector3>(Dali::Actor::Property::SIZE);
554 if(inheritanceModeList[i] == INHERIT_ALL)
556 localPosition = actorPosition + centerPosition + (parentOrigin - Vector3(0.5f, 0.5f, 0.5f)) * parentSize;
557 localMatrix.SetTransformComponents(localScale, localOrientation, localPosition);
559 //Update the world matrix
561 MatrixUtils::MultiplyTransformMatrix(tempMatrix, localMatrix, worldMatrix);
562 worldMatrix = tempMatrix;
566 Vector3 parentPosition, parentScale;
567 Quaternion parentOrientation;
568 worldMatrix.GetTransformComponents(parentPosition, parentOrientation, parentScale);
570 if((inheritanceModeList[i] & INHERIT_SCALE) == 0)
572 //Don't inherit scale
573 localScale /= parentScale;
576 if((inheritanceModeList[i] & INHERIT_ORIENTATION) == 0)
578 //Don't inherit orientation
579 parentOrientation.Invert();
580 localOrientation = parentOrientation * localOrientation;
583 if((inheritanceModeList[i] & INHERIT_POSITION) == 0)
585 localMatrix.SetTransformComponents(localScale, localOrientation, Vector3::ZERO);
587 MatrixUtils::Multiply(tempMatrix, localMatrix, worldMatrix);
588 worldMatrix = tempMatrix;
589 worldMatrix.SetTranslation(actorPosition + centerPosition);
593 localPosition = actorPosition + centerPosition + (parentOrigin - Vector3(0.5f, 0.5f, 0.5f)) * parentSize;
594 localMatrix.SetTransformComponents(localScale, localOrientation, localPosition);
596 MatrixUtils::Multiply(tempMatrix, localMatrix, worldMatrix);
597 worldMatrix = tempMatrix;
603 localPosition = actorPosition + centerPosition;
604 worldMatrix.SetTransformComponents(localScale, localOrientation, localPosition);
611 Vector4 CalculateActorWorldColor(const Actor& actor)
613 std::vector<Dali::Actor> descentList;
614 std::vector<Dali::ColorMode> inheritanceModeList;
615 Dali::Actor currentActor(const_cast<Actor*>(&actor));
616 Dali::ColorMode inheritance = Dali::ColorMode::USE_OWN_MULTIPLY_PARENT_ALPHA;
619 inheritance = currentActor.GetProperty<Dali::ColorMode>(Dali::Actor::Property::COLOR_MODE);
620 inheritanceModeList.push_back(inheritance);
621 descentList.push_back(currentActor);
622 currentActor = currentActor.GetParent();
623 } while(inheritance != Dali::ColorMode::USE_OWN_COLOR && currentActor);
626 const size_t descentCount = descentList.size();
627 for(size_t iter = 0u; iter < descentCount; ++iter)
629 auto i = descentCount - iter - 1u;
630 if(inheritanceModeList[i] == USE_OWN_COLOR || i == descentList.size() - 1)
632 worldColor = descentList[i].GetProperty<Vector4>(Dali::Actor::Property::COLOR);
634 else if(inheritanceModeList[i] == USE_OWN_MULTIPLY_PARENT_ALPHA)
636 Vector4 ownColor = descentList[i].GetProperty<Vector4>(Dali::Actor::Property::COLOR);
637 worldColor = Vector4(ownColor.r, ownColor.g, ownColor.b, ownColor.a * worldColor.a);
639 else if(inheritanceModeList[i] == USE_OWN_MULTIPLY_PARENT_COLOR)
641 Vector4 ownColor = descentList[i].GetProperty<Vector4>(Dali::Actor::Property::COLOR);
642 worldColor *= ownColor;
649 Quaternion CalculateActorLookAtOrientation(const Actor& actor, Vector3 target, Vector3 up, Vector3 localForward, Vector3 localUp)
651 Vector3 currentWorldPosition = CalculateActorWorldTransform(actor).GetTranslation3();
653 Quaternion worldToTarget = GetOrientationFromForwardAndUpVector(target - currentWorldPosition, up);
654 Quaternion worldToLocal = GetOrientationFromForwardAndUpVector(localForward, localUp);
656 // Rotate by this order : Local --> World --> Target
657 Quaternion ret = worldToTarget / worldToLocal;
659 // If we inherit orientation, get parent's world orientation, and revert it.
660 if(actor.IsOrientationInherited() && actor.GetParent())
662 // Get Parent information.
663 Vector3 parentPosition, parentScale;
664 Quaternion parentOrientation;
665 const Matrix& parentMatrix = CalculateActorWorldTransform(*actor.GetParent());
666 parentMatrix.GetTransformComponents(parentPosition, parentOrientation, parentScale);
668 ret = ret / parentOrientation;
674 } // namespace Dali::Internal