8957850a6fa57237d12333fa8422a75a50cb5524
[platform/core/uifw/dali-core.git] / dali / internal / event / actors / actor-coords.cpp
1 /*
2  * Copyright (c) 2023 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/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>
23
24 namespace Dali::Internal
25 {
26 namespace
27 {
28 /**
29  * @brief Get the Viewport Extents from RenderTask
30  *
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
34  */
35 bool GetViewportExtentsFromRenderTask(const RenderTask& renderTask, Rect<float>& viewportExtent)
36 {
37   if(renderTask.GetFrameBuffer())
38   {
39     Dali::Actor mappingActor = renderTask.GetScreenToFrameBufferMappingActor();
40     if(mappingActor)
41     {
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;
51     }
52     else
53     {
54       return false;
55     }
56   }
57   else
58   {
59     Viewport viewport;
60     renderTask.GetViewport(viewport);
61     viewportExtent.x      = viewport.x;
62     viewportExtent.y      = viewport.y;
63     viewportExtent.width  = viewport.width;
64     viewportExtent.height = viewport.height;
65   }
66   return true;
67 }
68
69 /**
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
73  *
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.
77  */
78 Quaternion GetOrientationFromForwardAndUpVector(Vector3 forward, Vector3 up)
79 {
80   Vector3 vZ = forward;
81   vZ.Normalize();
82
83   Vector3 vX = up.Cross(vZ);
84   vX.Normalize();
85
86   // If something invalid input comes, vX length become zero.
87   if(DALI_UNLIKELY(Dali::EqualsZero(vX.Length())))
88   {
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);
90     return Quaternion();
91   }
92
93   Vector3 vY = vZ.Cross(vX);
94   vY.Normalize();
95
96   return Quaternion(vX, vY, vZ);
97 }
98 } // namespace
99 bool ConvertScreenToLocal(
100   const Matrix&   viewMatrix,
101   const Matrix&   projectionMatrix,
102   const Matrix&   worldMatrix,
103   const Vector3&  currentSize,
104   const Viewport& viewport,
105   float&          localX,
106   float&          localY,
107   float           screenX,
108   float           screenY)
109 {
110   // Get the ModelView matrix
111   Matrix modelView;
112   MatrixUtils::MultiplyTransformMatrix(modelView, worldMatrix, viewMatrix);
113
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();
118
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);
121
122   Vector4 nearPos;
123   if(success)
124   {
125     success = Unproject(screenPos, invertedMvp, static_cast<float>(viewport.width), static_cast<float>(viewport.height), nearPos);
126   }
127
128   Vector4 farPos;
129   if(success)
130   {
131     screenPos.z = 1.0f;
132     success     = Unproject(screenPos, invertedMvp, static_cast<float>(viewport.width), static_cast<float>(viewport.height), farPos);
133   }
134
135   if(success)
136   {
137     Vector4 local;
138     if(XyPlaneIntersect(nearPos, farPos, local))
139     {
140       Vector3 size = currentSize;
141       localX       = local.x + size.x * 0.5f;
142       localY       = local.y + size.y * 0.5f;
143     }
144     else
145     {
146       success = false;
147     }
148   }
149
150   return success;
151 }
152
153 bool ConvertScreenToLocalRenderTask(
154   const RenderTask& renderTask,
155   const Matrix&     worldMatrix,
156   const Vector3&    currentSize,
157   float&            localX,
158   float&            localY,
159   float             screenX,
160   float             screenY)
161 {
162   bool         success = false;
163   CameraActor* camera  = renderTask.GetCameraActor();
164   if(camera)
165   {
166     Viewport viewport;
167     renderTask.GetViewport(viewport);
168
169     // need to translate coordinates to render tasks coordinate space
170     Vector2 converted(screenX, screenY);
171     if(renderTask.TranslateCoordinates(converted))
172     {
173       success = ConvertScreenToLocal(camera->GetViewMatrix(), camera->GetProjectionMatrix(), worldMatrix, currentSize, viewport, localX, localY, converted.x, converted.y);
174     }
175   }
176   return success;
177 }
178
179 bool ConvertScreenToLocalRenderTaskList(
180   const RenderTaskList& renderTaskList,
181   const Matrix&         worldMatrix,
182   const Vector3&        currentSize,
183   float&                localX,
184   float&                localY,
185   float                 screenX,
186   float                 screenY)
187 {
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)
191   {
192     RenderTaskPtr task = renderTaskList.GetTask(i - 1);
193     if(ConvertScreenToLocalRenderTask(*task, worldMatrix, currentSize, localX, localY, screenX, screenY))
194     {
195       // found a task where this conversion was ok so return
196       return true;
197     }
198   }
199   return false;
200 };
201
202 const Vector2 CalculateActorScreenPosition(const Actor& actor)
203 {
204   Vector2 result;
205   Scene&  scene = actor.GetScene();
206   if(actor.OnScene())
207   {
208     // TODO : Need to find way that we don't increase duplicated code, and did the same job.
209     auto worldTransformMatrix = Dali::Internal::CalculateActorWorldTransform(actor);
210
211     Vector3 worldPosition  = worldTransformMatrix.GetTranslation3();
212     Vector3 cameraPosition = Dali::Internal::CalculateActorWorldTransform(scene.GetDefaultCameraActor()).GetTranslation3();
213     worldPosition -= cameraPosition;
214
215     Vector3 actorSize = actor.GetTargetSize() * worldTransformMatrix.GetScale();
216     auto    sceneSize = scene.GetSize();
217     Vector2 halfSceneSize(sceneSize.width * 0.5f, sceneSize.height * 0.5f); // World position origin is center of scene
218     Vector3 halfActorSize(actorSize * 0.5f);
219     Vector3 anchorPointOffSet = halfActorSize - actorSize * actor.GetAnchorPointForPosition();
220
221     result = Vector2(halfSceneSize.width + worldPosition.x - anchorPointOffSet.x,
222                      halfSceneSize.height + worldPosition.y - anchorPointOffSet.y);
223   }
224   return result;
225 }
226
227 const Vector2 CalculateCurrentActorScreenPosition(const Actor& actor, BufferIndex bufferIndex)
228 {
229   Vector2 result;
230   Scene&  scene = actor.GetScene();
231   if(actor.OnScene())
232   {
233     // TODO : Need to find way that we don't increase duplicated code, and did the same job.
234     const auto& node           = actor.GetNode();
235     Vector3     worldPosition  = node.GetWorldPosition(bufferIndex);
236     Vector3     cameraPosition = scene.GetDefaultCameraActor().GetNode().GetWorldPosition(bufferIndex);
237     worldPosition -= cameraPosition;
238
239     Vector3 actorSize = node.GetSize(bufferIndex) * node.GetWorldScale(bufferIndex);
240     const auto& sceneSize = scene.GetCurrentSurfaceRect();                      // Use the update object's size
241     Vector2 halfSceneSize(sceneSize.width * 0.5f, sceneSize.height * 0.5f); // World position origin is center of scene
242     Vector3 halfActorSize(actorSize * 0.5f);
243     Vector3 anchorPointOffSet = halfActorSize - actorSize * actor.GetAnchorPointForPosition();
244
245     result = Vector2(halfSceneSize.width + worldPosition.x - anchorPointOffSet.x,
246                      halfSceneSize.height + worldPosition.y - anchorPointOffSet.y);
247   }
248   return result;
249 }
250
251 Rect<> CalculateActorScreenExtents(const Actor& actor)
252 {
253   // TODO : Need to find way that we don't increase duplicated code, and did the same job.
254   const Vector2 screenPosition = CalculateActorScreenPosition(actor);
255
256   auto worldTransformMatrix = Dali::Internal::CalculateActorWorldTransform(actor);
257
258   Vector3 size              = actor.GetTargetSize() * worldTransformMatrix.GetScale();
259   Vector3 anchorPointOffSet = size * actor.GetAnchorPointForPosition();
260   Vector2 position          = Vector2(screenPosition.x - anchorPointOffSet.x, screenPosition.y - anchorPointOffSet.y);
261   return {position.x, position.y, size.x, size.y};
262 }
263
264 Rect<> CalculateCurrentActorScreenExtents(const Actor& actor, BufferIndex bufferIndex)
265 {
266   // TODO : Need to find way that we don't increase duplicated code, and did the same job.
267   const Vector2 screenPosition = CalculateCurrentActorScreenPosition(actor, bufferIndex);
268
269   const auto& node              = actor.GetNode();
270   Vector3     size              = node.GetSize(bufferIndex) * node.GetWorldScale(bufferIndex);
271   Vector3     anchorPointOffSet = size * actor.GetAnchorPointForPosition();
272   Vector2     position          = Vector2(screenPosition.x - anchorPointOffSet.x, screenPosition.y - anchorPointOffSet.y);
273   return {position.x, position.y, size.x, size.y};
274 }
275
276 bool ConvertLocalToScreen(
277   const Matrix&  viewMatrix,
278   const Matrix&  projectionMatrix,
279   const Matrix&  worldMatrix,
280   const Rect<>&  viewportExtent,
281   const Vector3& localPosition,
282   float&         screenX,
283   float&         screenY)
284 {
285   bool success = false;
286
287   // Convert local to projection coordinates
288   // note, P*(V*(M*pos))) is faster than (P*V*M)*pos
289   Vector4 mvpPos(localPosition.x, localPosition.y, localPosition.z, 1.0f);
290
291   mvpPos = worldMatrix * mvpPos;
292   mvpPos = viewMatrix * mvpPos;
293   mvpPos = projectionMatrix * mvpPos;
294
295   if(DALI_LIKELY(!EqualsZero(mvpPos.w)))
296   {
297     success = true;
298     screenX = viewportExtent.x + (mvpPos.x + mvpPos.w) * viewportExtent.width * 0.5f / mvpPos.w;
299     screenY = viewportExtent.y + (-mvpPos.y + mvpPos.w) * viewportExtent.height * 0.5f / mvpPos.w;
300   }
301   return success;
302 }
303
304 bool ConvertLocalToScreenRenderTask(
305   const RenderTask& renderTask,
306   const Actor&      actor,
307   const Matrix&     worldMatrix,
308   const Vector3&    localPosition,
309   float&            screenX,
310   float&            screenY)
311 {
312   bool         success     = false;
313   const Actor* sourceActor = renderTask.GetSourceActor();
314   if(sourceActor == nullptr)
315   {
316     return success;
317   }
318
319   // Check whether current actor is in this rendertask.
320   bool         actorInRendertask = false;
321   const Actor* targetActor       = &actor;
322   while(targetActor)
323   {
324     if(sourceActor == targetActor)
325     {
326       actorInRendertask = true;
327       break;
328     }
329     targetActor = targetActor->GetParent();
330   }
331   if(!actorInRendertask)
332   {
333     return success;
334   }
335
336   CameraActor* camera = renderTask.GetCameraActor();
337   if(camera)
338   {
339     Rect<float> viewportExtent = {0.f, 0.f, 0.f, 0.f};
340     if(!GetViewportExtentsFromRenderTask(renderTask, viewportExtent))
341     {
342       return success;
343     }
344
345     if(ConvertLocalToScreen(camera->GetViewMatrix(), camera->GetProjectionMatrix(), worldMatrix, viewportExtent, localPosition, screenX, screenY))
346     {
347       success = true;
348     }
349   }
350   return success;
351 }
352
353 bool ConvertLocalToScreenRenderTaskList(
354   const RenderTaskList& renderTaskList,
355   const Actor&          actor,
356   const Matrix&         worldMatrix,
357   const Vector3&        localPosition,
358   float&                screenX,
359   float&                screenY)
360 {
361   // do a reverse traversal of all lists (as the default onscreen one is typically the last one)
362   uint32_t taskCount = renderTaskList.GetTaskCount();
363   for(uint32_t i = taskCount; i > 0; --i)
364   {
365     RenderTaskPtr task = renderTaskList.GetTask(i - 1);
366     if(ConvertLocalToScreenRenderTask(*task, actor, worldMatrix, localPosition, screenX, screenY))
367     {
368       // found a task where this conversion was ok so return
369       return true;
370     }
371   }
372   return false;
373 }
374
375 const Vector2 CalculateActorScreenPositionRenderTaskList(const Actor& actor)
376 {
377   Vector2 result;
378   if(actor.OnScene())
379   {
380     Scene& scene = actor.GetScene();
381
382     // TODO : Need to find way that we don't increase duplicated code, and did the same job.
383     auto        worldMatrix = Dali::Internal::CalculateActorWorldTransform(actor);
384     const auto& renderTaskList = scene.GetRenderTaskList();
385     ConvertLocalToScreenRenderTaskList(renderTaskList, actor, worldMatrix, actor.GetTargetSize() * (actor.GetAnchorPointForPosition() - Vector3(0.5f, 0.5f, 0.5f)), result.x, result.y);
386   }
387   return result;
388 }
389
390 const Vector2 CalculateCurrentActorScreenPositionRenderTaskList(const Actor& actor, BufferIndex bufferIndex)
391 {
392   Vector2 result;
393   if(actor.OnScene())
394   {
395     // TODO : Need to find way that we don't increase duplicated code, and did the same job.
396     const auto& node  = actor.GetNode();
397     Scene&      scene = actor.GetScene();
398
399     const auto& worldMatrix    = node.GetWorldMatrix(bufferIndex);
400     const auto& renderTaskList = scene.GetRenderTaskList();
401     ConvertLocalToScreenRenderTaskList(renderTaskList, actor, worldMatrix, node.GetSize(bufferIndex) * (actor.GetAnchorPointForPosition() - Vector3(0.5f, 0.5f, 0.5f)), result.x, result.y);
402   }
403   return result;
404 }
405
406 bool ConvertLocalToScreenExtentRenderTask(
407   const RenderTask& renderTask,
408   const Actor&      actor,
409   const Matrix&     worldMatrix,
410   const Vector3&    currentSize,
411   Rect<>&           screenExtent)
412 {
413   bool         success     = false;
414   const Actor* sourceActor = renderTask.GetSourceActor();
415   if(sourceActor == nullptr)
416   {
417     return success;
418   }
419
420   // Check whether current actor is in this rendertask.
421   bool         actorInRendertask = false;
422   const Actor* targetActor       = &actor;
423   while(targetActor)
424   {
425     if(sourceActor == targetActor)
426     {
427       actorInRendertask = true;
428       break;
429     }
430     targetActor = targetActor->GetParent();
431   }
432   if(!actorInRendertask)
433   {
434     return success;
435   }
436
437   CameraActor* camera = renderTask.GetCameraActor();
438   if(camera)
439   {
440     Rect<float> viewportExtent = {0.f, 0.f, 0.f, 0.f};
441     if(!GetViewportExtentsFromRenderTask(renderTask, viewportExtent))
442     {
443       return success;
444     }
445
446     constexpr uint32_t BOX_POINT_COUNT           = 8;
447     const Vector3      BBOffset[BOX_POINT_COUNT] = {
448       Vector3(-currentSize.width * 0.5f, -currentSize.height * 0.5f, -currentSize.depth * 0.5f),
449       Vector3(-currentSize.width * 0.5f, currentSize.height * 0.5f, -currentSize.depth * 0.5f),
450       Vector3(currentSize.width * 0.5f, -currentSize.height * 0.5f, -currentSize.depth * 0.5f),
451       Vector3(currentSize.width * 0.5f, currentSize.height * 0.5f, -currentSize.depth * 0.5f),
452       Vector3(-currentSize.width * 0.5f, -currentSize.height * 0.5f, currentSize.depth * 0.5f),
453       Vector3(-currentSize.width * 0.5f, currentSize.height * 0.5f, currentSize.depth * 0.5f),
454       Vector3(currentSize.width * 0.5f, -currentSize.height * 0.5f, currentSize.depth * 0.5f),
455       Vector3(currentSize.width * 0.5f, currentSize.height * 0.5f, currentSize.depth * 0.5f),
456     };
457
458     float minScreenX = 0.0f;
459     float minScreenY = 0.0f;
460     float maxScreenX = 0.0f;
461     float maxScreenY = 0.0f;
462
463     const auto& viewMatrix       = camera->GetViewMatrix();
464     const auto& projectionMatrix = camera->GetProjectionMatrix();
465
466     success = ConvertLocalToScreen(viewMatrix, projectionMatrix, worldMatrix, viewportExtent, BBOffset[0], minScreenX, minScreenY);
467     if(success)
468     {
469       maxScreenX = minScreenX;
470       maxScreenY = minScreenY;
471       for(uint32_t i = 1; i < BOX_POINT_COUNT; ++i)
472       {
473         float   screenX       = 0.0f;
474         float   screenY       = 0.0f;
475         Vector3 localPosition = BBOffset[i];
476         if(DALI_UNLIKELY(!ConvertLocalToScreen(viewMatrix, projectionMatrix, worldMatrix, viewportExtent, localPosition, screenX, screenY)))
477         {
478           success = false;
479           break;
480         }
481         minScreenX = std::min(minScreenX, screenX);
482         maxScreenX = std::max(maxScreenX, screenX);
483         minScreenY = std::min(minScreenY, screenY);
484         maxScreenY = std::max(maxScreenY, screenY);
485       }
486       if(success)
487       {
488         screenExtent.x      = minScreenX;
489         screenExtent.y      = minScreenY;
490         screenExtent.width  = maxScreenX - minScreenX;
491         screenExtent.height = maxScreenY - minScreenY;
492       }
493     }
494   }
495   return success;
496 }
497
498 bool ConvertLocalToScreenExtentRenderTaskList(
499   const RenderTaskList& renderTaskList,
500   const Actor&          actor,
501   const Matrix&         worldMatrix,
502   const Vector3&        currentSize,
503   Rect<>&               screenExtent)
504 {
505   // do a reverse traversal of all lists (as the default onscreen one is typically the last one)
506   uint32_t taskCount = renderTaskList.GetTaskCount();
507   for(uint32_t i = taskCount; i > 0; --i)
508   {
509     RenderTaskPtr task = renderTaskList.GetTask(i - 1);
510     if(ConvertLocalToScreenExtentRenderTask(*task, actor, worldMatrix, currentSize, screenExtent))
511     {
512       // found a task where this conversion was ok so return
513       return true;
514     }
515   }
516   return false;
517 }
518
519 Rect<> CalculateActorScreenExtentsRenderTaskList(const Actor& actor)
520 {
521   Rect<> result = {0.0f, 0.0f, 0.0f, 0.0f};
522
523   if(actor.OnScene())
524   {
525     Scene& scene = actor.GetScene();
526
527     auto        worldMatrix    = Dali::Internal::CalculateActorWorldTransform(actor);
528     const auto& renderTaskList = scene.GetRenderTaskList();
529     ConvertLocalToScreenExtentRenderTaskList(renderTaskList, actor, worldMatrix, actor.GetTargetSize(), result);
530   }
531   return result;
532 }
533
534 Rect<> CalculateCurrentActorScreenExtentsRenderTaskList(const Actor& actor, BufferIndex bufferIndex)
535 {
536   Rect<> result = {0.0f, 0.0f, 0.0f, 0.0f};
537
538   if(actor.OnScene())
539   {
540     const auto& node  = actor.GetNode();
541     Scene&      scene = actor.GetScene();
542
543     const auto& worldMatrix    = node.GetWorldMatrix(bufferIndex);
544     const auto& renderTaskList = scene.GetRenderTaskList();
545     ConvertLocalToScreenExtentRenderTaskList(renderTaskList, actor, worldMatrix, node.GetSize(bufferIndex), result);
546   }
547   return result;
548 }
549
550 /**
551  * @brief Computes and center position by using transform properties.
552  * @param[in] anchorPoint anchorPoint of an actor.
553  * @param[in] positionUsesAnchorPoint positionUsesAnchorPoint of an actor.
554  * @param[in] size size of an actor.
555  * @param[in] scale scale of an actor.
556  * @param[in] orientation orientation of an actor.
557  */
558 Vector3 CalculateCenterPosition(
559   const Vector3&    anchorPoint,
560   const bool        positionUsesAnchorPoint,
561   const Vector3&    size,
562   const Vector3&    scale,
563   const Quaternion& orientation)
564 {
565   Vector3       centerPosition;
566   const Vector3 half(0.5f, 0.5f, 0.5f);
567   const Vector3 topLeft(0.0f, 0.0f, 0.5f);
568   // Calculate the center-point by applying the scale and rotation on the anchor point.
569   centerPosition = (half - anchorPoint) * size * scale;
570   centerPosition *= orientation;
571
572   // If the position is ignoring the anchor-point, then remove the anchor-point shift from the position.
573   if(!positionUsesAnchorPoint)
574   {
575     centerPosition -= (topLeft - anchorPoint) * size;
576   }
577   return centerPosition;
578 }
579
580 Matrix CalculateActorWorldTransform(const Actor& actor)
581 {
582   enum InheritanceMode
583   {
584     DONT_INHERIT_TRANSFORM = 0,
585     INHERIT_POSITION       = 1,
586     INHERIT_SCALE          = 2,
587     INHERIT_ORIENTATION    = 4,
588     INHERIT_ALL            = INHERIT_POSITION | INHERIT_SCALE | INHERIT_ORIENTATION,
589   };
590
591   std::vector<Dali::Actor>     descentList;
592   std::vector<InheritanceMode> inheritanceModeList;
593   Dali::Actor                  currentActor(const_cast<Actor*>(&actor));
594   int                          inheritance = 0;
595   do
596   {
597     inheritance = (static_cast<int>(currentActor.GetProperty<bool>(Dali::Actor::Property::INHERIT_ORIENTATION)) << 2) +
598                   (static_cast<int>(currentActor.GetProperty<bool>(Dali::Actor::Property::INHERIT_SCALE)) << 1) +
599                   static_cast<int>(currentActor.GetProperty<bool>(Dali::Actor::Property::INHERIT_POSITION));
600     inheritanceModeList.push_back(static_cast<InheritanceMode>(inheritance));
601     descentList.push_back(currentActor);
602     currentActor = currentActor.GetParent();
603   } while(inheritance != DONT_INHERIT_TRANSFORM && currentActor);
604
605   Matrix  worldMatrix;
606   Vector3 localPosition;
607
608   // descentList is leaf first, so traverse from root (end) to leaf (beginning)
609   const size_t descentCount = descentList.size();
610   for(size_t iter = 0u; iter < descentCount; ++iter)
611   {
612     auto       i                       = descentCount - iter - 1u;
613     Vector3    anchorPoint             = descentList[i].GetProperty<Vector3>(Dali::Actor::Property::ANCHOR_POINT);
614     Vector3    parentOrigin            = descentList[i].GetProperty<Vector3>(Dali::Actor::Property::PARENT_ORIGIN);
615     bool       positionUsesAnchorPoint = descentList[i].GetProperty<bool>(Dali::Actor::Property::POSITION_USES_ANCHOR_POINT);
616     Vector3    size                    = descentList[i].GetProperty<Vector3>(Dali::Actor::Property::SIZE);
617     Vector3    actorPosition           = descentList[i].GetProperty<Vector3>(Dali::Actor::Property::POSITION);
618     Quaternion localOrientation        = descentList[i].GetProperty<Quaternion>(Dali::Actor::Property::ORIENTATION);
619     Vector3    localScale              = descentList[i].GetProperty<Vector3>(Dali::Actor::Property::SCALE);
620
621     Vector3 centerPosition = CalculateCenterPosition(anchorPoint, positionUsesAnchorPoint, size, localScale, localOrientation);
622     if(inheritanceModeList[i] != DONT_INHERIT_TRANSFORM && descentList[i].GetParent())
623     {
624       Matrix  localMatrix;
625       Vector3 parentSize = descentList[i + 1].GetProperty<Vector3>(Dali::Actor::Property::SIZE);
626       if(inheritanceModeList[i] == INHERIT_ALL)
627       {
628         localPosition = actorPosition + centerPosition + (parentOrigin - Vector3(0.5f, 0.5f, 0.5f)) * parentSize;
629         localMatrix.SetTransformComponents(localScale, localOrientation, localPosition);
630
631         //Update the world matrix
632         Matrix tempMatrix;
633         MatrixUtils::MultiplyTransformMatrix(tempMatrix, localMatrix, worldMatrix);
634         worldMatrix = tempMatrix;
635       }
636       else
637       {
638         // Get Parent information.
639         Vector3       parentPosition, parentScale;
640         Quaternion    parentOrientation;
641         const Matrix& parentMatrix = worldMatrix;
642         parentMatrix.GetTransformComponents(parentPosition, parentOrientation, parentScale);
643
644         // Compute intermediate Local information
645         centerPosition                    = CalculateCenterPosition(anchorPoint, positionUsesAnchorPoint, size, localScale, localOrientation);
646         Vector3 intermediateLocalPosition = actorPosition + centerPosition + (parentOrigin - Vector3(0.5f, 0.5f, 0.5f)) * parentSize;
647         Matrix  intermediateLocalMatrix;
648         intermediateLocalMatrix.SetTransformComponents(localScale, localOrientation, intermediateLocalPosition);
649
650         // Compute intermediate world information
651         Matrix intermediateWorldMatrix;
652         MatrixUtils::MultiplyTransformMatrix(intermediateWorldMatrix, intermediateLocalMatrix, parentMatrix);
653
654         Vector3    intermediateWorldPosition, intermediateWorldScale;
655         Quaternion intermediateWorldOrientation;
656         intermediateWorldMatrix.GetTransformComponents(intermediateWorldPosition, intermediateWorldOrientation, intermediateWorldScale);
657
658         // Compute final world information
659         Vector3    finalWorldPosition    = intermediateWorldPosition;
660         Vector3    finalWorldScale       = intermediateWorldScale;
661         Quaternion finalWorldOrientation = intermediateWorldOrientation;
662         // worldScale includes the influence of local scale, local rotation, and parent scale.
663         // So, for the final world matrix, if this node inherits its parent scale, use worldScale.
664         // If not, use local scale for the final world matrix.
665         if((inheritanceModeList[i] & INHERIT_SCALE) == 0)
666         {
667           finalWorldScale = localScale;
668         }
669
670         // For the final world matrix, if this node inherits its parent orientation, use worldOrientation.
671         // If not, use local orientation for the final world matrix.
672         if((inheritanceModeList[i] & INHERIT_ORIENTATION) == 0)
673         {
674           finalWorldOrientation = localOrientation;
675         }
676
677         // The final world position of this node is computed as a sum of
678         // parent origin position in world space and relative position of center from parent origin.
679         // If this node doesn't inherit its parent position, simply use the relative position as a final world position.
680         Vector3 localCenterPosition = CalculateCenterPosition(anchorPoint, positionUsesAnchorPoint, size, finalWorldScale, finalWorldOrientation);
681         finalWorldPosition          = actorPosition * finalWorldScale;
682         finalWorldPosition *= finalWorldOrientation;
683         finalWorldPosition += localCenterPosition;
684         if((inheritanceModeList[i] & INHERIT_POSITION) != 0)
685         {
686           Vector4 parentOriginPosition((parentOrigin - Vector3(0.5f, 0.5f, 0.5f)) * parentSize);
687           parentOriginPosition.w = 1.0f;
688           finalWorldPosition += Vector3(parentMatrix * parentOriginPosition);
689         }
690
691         worldMatrix.SetTransformComponents(finalWorldScale, finalWorldOrientation, finalWorldPosition);
692       }
693     }
694     else
695     {
696       localPosition = actorPosition + centerPosition;
697       worldMatrix.SetTransformComponents(localScale, localOrientation, localPosition);
698     }
699   }
700
701   return worldMatrix;
702 }
703
704 Vector4 CalculateActorWorldColor(const Actor& actor)
705 {
706   std::vector<Dali::Actor>     descentList;
707   std::vector<Dali::ColorMode> inheritanceModeList;
708   Dali::Actor                  currentActor(const_cast<Actor*>(&actor));
709   Dali::ColorMode              inheritance = Dali::ColorMode::USE_OWN_MULTIPLY_PARENT_ALPHA;
710   do
711   {
712     inheritance = currentActor.GetProperty<Dali::ColorMode>(Dali::Actor::Property::COLOR_MODE);
713     inheritanceModeList.push_back(inheritance);
714     descentList.push_back(currentActor);
715     currentActor = currentActor.GetParent();
716   } while(inheritance != Dali::ColorMode::USE_OWN_COLOR && currentActor);
717
718   Vector4      worldColor;
719   const size_t descentCount = descentList.size();
720   for(size_t iter = 0u; iter < descentCount; ++iter)
721   {
722     auto i = descentCount - iter - 1u;
723     if(inheritanceModeList[i] == USE_OWN_COLOR || i == descentList.size() - 1)
724     {
725       worldColor = descentList[i].GetProperty<Vector4>(Dali::Actor::Property::COLOR);
726     }
727     else if(inheritanceModeList[i] == USE_OWN_MULTIPLY_PARENT_ALPHA)
728     {
729       Vector4 ownColor = descentList[i].GetProperty<Vector4>(Dali::Actor::Property::COLOR);
730       worldColor       = Vector4(ownColor.r, ownColor.g, ownColor.b, ownColor.a * worldColor.a);
731     }
732     else if(inheritanceModeList[i] == USE_OWN_MULTIPLY_PARENT_COLOR)
733     {
734       Vector4 ownColor = descentList[i].GetProperty<Vector4>(Dali::Actor::Property::COLOR);
735       worldColor *= ownColor;
736     }
737   }
738
739   return worldColor;
740 }
741
742 Quaternion CalculateActorLookAtOrientation(const Actor& actor, Vector3 target, Vector3 up, Vector3 localForward, Vector3 localUp)
743 {
744   Vector3 currentWorldPosition = Dali::Internal::CalculateActorWorldTransform(actor).GetTranslation3();
745
746   Quaternion worldToTarget = GetOrientationFromForwardAndUpVector(target - currentWorldPosition, up);
747   Quaternion worldToLocal  = GetOrientationFromForwardAndUpVector(localForward, localUp);
748
749   // Rotate by this order : Local --> World --> Target
750   Quaternion ret = worldToTarget / worldToLocal;
751
752   // If we inherit orientation, get parent's world orientation, and revert it.
753   if(actor.IsOrientationInherited() && actor.GetParent())
754   {
755     // Get Parent information.
756     Vector3       parentPosition, parentScale;
757     Quaternion    parentOrientation;
758     const Matrix& parentMatrix = Dali::Internal::CalculateActorWorldTransform(*actor.GetParent());
759     parentMatrix.GetTransformComponents(parentPosition, parentOrientation, parentScale);
760
761     ret = ret / parentOrientation;
762   }
763
764   return ret;
765 }
766
767 } // namespace Dali::Internal