Fix surface deletion order issue
[platform/core/uifw/dali-core.git] / dali / internal / event / actors / camera-actor-impl.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
18 // CLASS HEADER
19 #include <dali/internal/event/actors/camera-actor-impl.h>
20
21 // EXTERNAL INCLUDES
22 #include <cmath>
23 #include <cstring> // for strcmp
24
25 // INTERNAL INCLUDES
26 #include <dali/devel-api/actors/camera-actor-devel.h>
27 #include <dali/internal/common/matrix-utils.h>
28 #include <dali/internal/event/common/projection.h>
29 #include <dali/internal/event/common/property-helper.h>
30 #include <dali/internal/event/common/thread-local-storage.h>
31 #include <dali/public-api/object/type-registry.h>
32
33 #include <dali/internal/update/common/property-base.h>
34 #include <dali/internal/update/manager/update-manager.h>
35 #include <dali/internal/update/render-tasks/scene-graph-camera-messages.h>
36
37 namespace Dali
38 {
39 namespace Internal
40 {
41 namespace
42 {
43 // Properties
44
45 /**
46  * We want to discourage the use of property strings (minimize string comparisons),
47  * particularly for the default properties.
48  *              Name                     Type   writable animatable constraint-input  enum for index-checking
49  */
50 // clang-format off
51 DALI_PROPERTY_TABLE_BEGIN
52 DALI_PROPERTY( "type",                   INTEGER,  true,    false,   true,   Dali::CameraActor::Property::TYPE                      )
53 DALI_PROPERTY( "projectionMode",         INTEGER,  true,    false,   true,   Dali::CameraActor::Property::PROJECTION_MODE           )
54 DALI_PROPERTY( "fieldOfView",            FLOAT,    true,    true,    true,   Dali::CameraActor::Property::FIELD_OF_VIEW             )
55 DALI_PROPERTY( "aspectRatio",            FLOAT,    true,    true,    true,   Dali::CameraActor::Property::ASPECT_RATIO              )
56 DALI_PROPERTY( "nearPlaneDistance",      FLOAT,    true,    false,   true,   Dali::CameraActor::Property::NEAR_PLANE_DISTANCE       )
57 DALI_PROPERTY( "farPlaneDistance",       FLOAT,    true,    false,   true,   Dali::CameraActor::Property::FAR_PLANE_DISTANCE        )
58 DALI_PROPERTY( "leftPlaneDistance",      FLOAT,    false,   false,   true,   Dali::CameraActor::Property::LEFT_PLANE_DISTANCE       )
59 DALI_PROPERTY( "rightPlaneDistance",     FLOAT,    false,   false,   true,   Dali::CameraActor::Property::RIGHT_PLANE_DISTANCE      )
60 DALI_PROPERTY( "topPlaneDistance",       FLOAT,    false,   false,   true,   Dali::CameraActor::Property::TOP_PLANE_DISTANCE        )
61 DALI_PROPERTY( "bottomPlaneDistance",    FLOAT,    false,   false,   true,   Dali::CameraActor::Property::BOTTOM_PLANE_DISTANCE     )
62 DALI_PROPERTY( "targetPosition",         VECTOR3,  true,    false,   true,   Dali::CameraActor::Property::TARGET_POSITION           )
63 DALI_PROPERTY( "projectionMatrix",       MATRIX,   false,   false,   true,   Dali::CameraActor::Property::PROJECTION_MATRIX         )
64 DALI_PROPERTY( "viewMatrix",             MATRIX,   false,   false,   true,   Dali::CameraActor::Property::VIEW_MATRIX               )
65 DALI_PROPERTY( "invertYAxis",            BOOLEAN,  true,    false,   true,   Dali::CameraActor::Property::INVERT_Y_AXIS             )
66 DALI_PROPERTY( "orthographicSize",       FLOAT,    true,    true,    true,   Dali::DevelCameraActor::Property::ORTHOGRAPHIC_SIZE    )
67 DALI_PROPERTY( "projectionDirection",    INTEGER,  true,    false,   true,   Dali::DevelCameraActor::Property::PROJECTION_DIRECTION )
68 DALI_PROPERTY_TABLE_END( DEFAULT_DERIVED_ACTOR_PROPERTY_START_INDEX, CameraDefaultProperties )
69 // clang-format on
70
71 // calculate the far plane distance for a 16bit depth buffer with 4 bits per unit precision
72 void CalculateClippingAndZ(float width, float height, float& nearClippingPlane, float& farClippingPlane, float& cameraZ)
73 {
74   nearClippingPlane = std::max(width, height);
75   farClippingPlane  = nearClippingPlane + static_cast<float>(0xFFFF >> 4);
76   cameraZ           = 2.0f * nearClippingPlane;
77 }
78
79 BaseHandle Create()
80 {
81   return Dali::CameraActor::New();
82 }
83
84 TypeRegistration mType(typeid(Dali::CameraActor), typeid(Dali::Actor), Create, CameraDefaultProperties);
85
86 /**
87  * Builds the picking ray in the world reference system from an orthographic camera
88  * The ray origin is the screen coordinate in the near plane translated to a parallel
89  * plane at the camera origin. The ray direction is the direction the camera is facing
90  * (i.e. Z=-1 in view space).
91  */
92 void BuildOrthoPickingRay(const Matrix&   viewMatrix,
93                           const Matrix&   projectionMatrix,
94                           const Viewport& viewport,
95                           float           screenX,
96                           float           screenY,
97                           Vector4&        rayOrigin,
98                           Vector4&        rayDir,
99                           float           nearPlaneDistance)
100 {
101   //          inv( modelMatrix )          inv( viewMatrix )    inv( projectionMatrix )           normalize
102   //          <-----------------         <-----------------         <--------------           <-------------
103   //  Local                      World                      Camera                 Normalized                 Screen
104   // reference                  reference                  reference                  clip                  coordinates
105   //  system                     system                     system                 coordinates
106   //          ----------------->         ----------------->         -------------->           ------------->
107   //             modelMatrix                 viewMatrix             projectionMatrix             viewport
108
109   // Transforms the touch point from the screen reference system to the world reference system.
110   Matrix invViewProjection(false); // Don't initialize.
111   MatrixUtils::MultiplyProjectionMatrix(invViewProjection, viewMatrix, projectionMatrix);
112   if(!invViewProjection.Invert())
113   {
114     DALI_ASSERT_DEBUG(false);
115   }
116
117   Vector4 near(screenX - static_cast<float>(viewport.x),
118                static_cast<float>(viewport.height) - (screenY - static_cast<float>(viewport.y)),
119                0.f,
120                1.f);
121   if(!Unproject(near, invViewProjection, static_cast<float>(viewport.width), static_cast<float>(viewport.height), rayOrigin))
122   {
123     DALI_ASSERT_DEBUG(false);
124   }
125
126   Matrix invView = viewMatrix;
127   if(!invView.Invert())
128   {
129     DALI_ASSERT_DEBUG(false);
130   }
131
132   Vector4 cameraOrigin    = invView * Vector4(0.f, 0.f, 0.f, 1.f);
133   Vector4 nearPlaneOrigin = invView * Vector4(0.0f, 0.0f, -nearPlaneDistance, 1.0f);
134
135   // Vector pointing from the camera to the near plane
136   rayDir = cameraOrigin - nearPlaneOrigin;
137   rayOrigin -= rayDir;
138   rayDir.Normalize();
139   rayDir.w = 1.0f;
140 }
141
142 /**
143  * @brief Helper class to calculate left/right/top/bottom plane distance by orthographicSize and something other info.
144  * It will resolve some confuse case of plane distance value.
145  * (Something like, Is top plane distance is positive or negative? is aspect ratio is width/height or height/width?)
146  */
147 struct OrthographicSizeConverter
148 {
149   constexpr OrthographicSizeConverter(float orthographicSize, float aspectRatio, Dali::DevelCameraActor::ProjectionDirection projectionDirection)
150   : mOrthographicSize(orthographicSize),
151     mAspectRatio(aspectRatio),
152     mProjectionDirection(projectionDirection)
153   {
154   }
155
156   inline float LeftPlaneDistance() const
157   {
158     return -(mProjectionDirection == DevelCameraActor::ProjectionDirection::VERTICAL ? mOrthographicSize * mAspectRatio : mOrthographicSize);
159   }
160
161   inline float RightPlaneDistance() const
162   {
163     return (mProjectionDirection == DevelCameraActor::ProjectionDirection::VERTICAL ? mOrthographicSize * mAspectRatio : mOrthographicSize);
164   }
165
166   inline float TopPlaneDistance() const
167   {
168     return (mProjectionDirection == DevelCameraActor::ProjectionDirection::VERTICAL ? mOrthographicSize : mOrthographicSize / mAspectRatio);
169   }
170
171   inline float BottomPlaneDistance() const
172   {
173     return -(mProjectionDirection == DevelCameraActor::ProjectionDirection::VERTICAL ? mOrthographicSize : mOrthographicSize / mAspectRatio);
174   }
175
176   float                                       mOrthographicSize;
177   float                                       mAspectRatio;
178   Dali::DevelCameraActor::ProjectionDirection mProjectionDirection;
179 };
180
181 static const float DEFAULT_NEAR_CLIPPING_PLANE_FOR_3D = 0.1f;
182 static const float DEFAULT_FAR_CLIPPING_PLANE_FOR_3D  = 100.0f;
183
184 static const Dali::Camera::ProjectionMode                DEFAULT_MODE_FOR_3D                 = SceneGraph::Camera::DEFAULT_MODE;
185 static const Dali::DevelCameraActor::ProjectionDirection DEFAULT_PROJECTION_DIRECTION_FOR_3D = SceneGraph::Camera::DEFAULT_PROJECTION_DIRECTION;
186
187 static const float      DEFAULT_FIELD_OF_VIEW_FOR_3D     = SceneGraph::Camera::DEFAULT_FIELD_OF_VIEW;
188 static const float      DEFAULT_POSITIN_Z_FOR_3D         = 5.0f;
189 static const Quaternion DEFAULT_ORIENTATION_FOR_3D       = Quaternion(Dali::ANGLE_180, Vector3::YAXIS);
190 static const float      DEFAULT_ORTHOGRAPHIC_SIZE_FOR_3D = 2.071068f; // DEFAULT_POSITIN_Z_FOR_3D * std::tan(DEFAULT_FIELD_OF_VIEW_FOR_3D * 0.5f); // Rectangle size of z=0.
191
192 /**
193  * @brief Setup CameraActor's parameters  for 3D apps.
194  * Conceptually, We can must see 1 world unit cube at world origin.
195  * Detail value can be changed by UX.
196  *
197  * @param[in,out] cameraActorObject CameraActor who need to apply default camera parameters.
198  */
199 void SetupDefault3DCameraProperties(Internal::CameraActor& cameraActorObject)
200 {
201   cameraActorObject.SetNearClippingPlane(DEFAULT_NEAR_CLIPPING_PLANE_FOR_3D);
202   cameraActorObject.SetFarClippingPlane(DEFAULT_FAR_CLIPPING_PLANE_FOR_3D);
203
204   cameraActorObject.SetProjectionMode(DEFAULT_MODE_FOR_3D);
205   cameraActorObject.SetProjectionDirection(DEFAULT_PROJECTION_DIRECTION_FOR_3D);
206   cameraActorObject.SetFieldOfView(DEFAULT_FIELD_OF_VIEW_FOR_3D);
207   cameraActorObject.SetZ(DEFAULT_POSITIN_Z_FOR_3D);
208   cameraActorObject.SetOrientation(DEFAULT_ORIENTATION_FOR_3D);
209
210   cameraActorObject.SetOrthographicSize(DEFAULT_ORTHOGRAPHIC_SIZE_FOR_3D);
211 }
212
213 } // namespace
214
215 CameraActorPtr CameraActor::New(const Size& size, bool hintFor3D)
216 {
217   // create camera. Cameras are owned by the update manager
218   SceneGraph::Camera*            camera = SceneGraph::Camera::New();
219   OwnerPointer<SceneGraph::Node> transferOwnership(camera);
220   Internal::ThreadLocalStorage*  tls = Internal::ThreadLocalStorage::GetInternal();
221
222   DALI_ASSERT_ALWAYS(tls && "ThreadLocalStorage is null");
223
224   // Send ownership of camera.
225   AddNodeMessage(tls->GetUpdateManager(), transferOwnership);
226
227   CameraActorPtr actor(new CameraActor(*camera));
228
229   // Second-phase construction
230   actor->Initialize();
231
232   actor->SetName("DefaultCamera");
233   if(hintFor3D)
234   {
235     // Initialize camera property for 3D case.
236     SetupDefault3DCameraProperties(*actor);
237   }
238   else
239   {
240     actor->SetPerspectiveProjection(size);
241
242     // By default Actors face in the positive Z direction in world space
243     // CameraActors should face in the negative Z direction, towards the other actors
244     actor->SetOrientation(Quaternion(Dali::ANGLE_180, Vector3::YAXIS));
245   }
246
247   return actor;
248 }
249
250 CameraActor::CameraActor(const SceneGraph::Node& node)
251 : Actor(Actor::BASIC, node),
252   mTarget(SceneGraph::Camera::DEFAULT_TARGET_POSITION),
253   mType(SceneGraph::Camera::DEFAULT_TYPE),
254   mProjectionMode(SceneGraph::Camera::DEFAULT_MODE),
255   mProjectionDirection(SceneGraph::Camera::DEFAULT_PROJECTION_DIRECTION),
256   mFieldOfView(SceneGraph::Camera::DEFAULT_FIELD_OF_VIEW),
257   mOrthographicSize(SceneGraph::Camera::DEFAULT_ORTHOGRAPHIC_SIZE),
258   mAspectRatio(SceneGraph::Camera::DEFAULT_ASPECT_RATIO),
259   mNearClippingPlane(SceneGraph::Camera::DEFAULT_NEAR_CLIPPING_PLANE),
260   mFarClippingPlane(SceneGraph::Camera::DEFAULT_FAR_CLIPPING_PLANE),
261   mInvertYAxis(SceneGraph::Camera::DEFAULT_INVERT_Y_AXIS),
262   mPropertyChanged(false)
263 {
264 }
265
266 CameraActor::~CameraActor()
267 {
268 }
269
270 void CameraActor::OnSceneConnectionInternal()
271 {
272   // If the canvas size has not been set, then use the size of the scene to which we've been added
273   // in order to set up the current projection
274   if(!mPropertyChanged && ((mCanvasSize.width < Math::MACHINE_EPSILON_1000) || (mCanvasSize.height < Math::MACHINE_EPSILON_1000)))
275   {
276     if(mProjectionMode == Dali::Camera::ORTHOGRAPHIC_PROJECTION)
277     {
278       SetOrthographicProjection(GetScene().GetSize());
279     }
280     else //if(mProjectionMode == Dali::Camera::PERSPECTIVE_PROJECTION)
281     {
282       SetPerspectiveProjection(GetScene().GetSize());
283     }
284   }
285 }
286
287 void CameraActor::SetReflectByPlane(const Vector4& plane)
288 {
289   SetReflectByPlaneMessage(GetEventThreadServices(), GetCameraSceneObject(), plane);
290 }
291
292 void CameraActor::SetTarget(const Vector3& target)
293 {
294   mPropertyChanged = true;
295   if(target != mTarget) // using range epsilon
296   {
297     mTarget = target;
298
299     SetTargetPositionMessage(GetEventThreadServices(), GetCameraSceneObject(), mTarget);
300   }
301 }
302
303 Vector3 CameraActor::GetTarget() const
304 {
305   return mTarget;
306 }
307
308 void CameraActor::SetType(Dali::Camera::Type type)
309 {
310   if(type != mType)
311   {
312     mType = type;
313
314     // sceneObject is being used in a separate thread; queue a message to set
315     SetTypeMessage(GetEventThreadServices(), GetCameraSceneObject(), mType);
316   }
317 }
318
319 Dali::Camera::Type CameraActor::GetType() const
320 {
321   return mType;
322 }
323
324 void CameraActor::SetProjectionMode(Dali::Camera::ProjectionMode mode)
325 {
326   if(mode != mProjectionMode)
327   {
328     mProjectionMode = mode;
329
330     // sceneObject is being used in a separate thread; queue a message to set
331     SetProjectionModeMessage(GetEventThreadServices(), GetCameraSceneObject(), mProjectionMode);
332   }
333 }
334
335 Dali::Camera::ProjectionMode CameraActor::GetProjectionMode() const
336 {
337   return mProjectionMode;
338 }
339
340 void CameraActor::SetProjectionDirection(Dali::DevelCameraActor::ProjectionDirection direction)
341 {
342   mPropertyChanged = true;
343   if(direction != mProjectionDirection)
344   {
345     mProjectionDirection = direction;
346
347     // sceneObject is being used in a separate thread; queue a message to set
348     SetProjectionDirectionMessage(GetEventThreadServices(), GetCameraSceneObject(), mProjectionDirection);
349   }
350 }
351
352 void CameraActor::SetFieldOfView(float fieldOfView)
353 {
354   mPropertyChanged = true;
355   if(!Equals(fieldOfView, mFieldOfView))
356   {
357     mFieldOfView = fieldOfView;
358
359     // sceneObject is being used in a separate thread; queue a message to set
360     BakeFieldOfViewMessage(GetEventThreadServices(), GetCameraSceneObject(), mFieldOfView);
361   }
362 }
363
364 float CameraActor::GetFieldOfView() const
365 {
366   return mFieldOfView;
367 }
368
369 float CameraActor::GetCurrentFieldOfView() const
370 {
371   // node is being used in a separate thread; copy the value from the previous update
372   return GetCameraSceneObject().GetFieldOfView(GetEventThreadServices().GetEventBufferIndex());
373 }
374
375 void CameraActor::SetOrthographicSize(float orthographicSize)
376 {
377   mPropertyChanged = true;
378   if(!Equals(orthographicSize, mOrthographicSize))
379   {
380     mOrthographicSize = orthographicSize;
381
382     // sceneObject is being used in a separate thread; queue a message to set
383     BakeOrthographicSizeMessage(GetEventThreadServices(), GetCameraSceneObject(), mOrthographicSize);
384   }
385 }
386
387 float CameraActor::GetOrthographicSize() const
388 {
389   return mOrthographicSize;
390 }
391
392 float CameraActor::GetCurrentOrthographicSize() const
393 {
394   // node is being used in a separate thread; copy the value from the previous update
395   return GetCameraSceneObject().GetOrthographicSize(GetEventThreadServices().GetEventBufferIndex());
396 }
397
398 void CameraActor::SetAspectRatio(float aspectRatio)
399 {
400   mPropertyChanged = true;
401   if(!Equals(aspectRatio, mAspectRatio))
402   {
403     mAspectRatio = aspectRatio;
404
405     // sceneObject is being used in a separate thread; queue a message to set
406     BakeAspectRatioMessage(GetEventThreadServices(), GetCameraSceneObject(), mAspectRatio);
407   }
408 }
409
410 float CameraActor::GetAspectRatio() const
411 {
412   return mAspectRatio;
413 }
414
415 float CameraActor::GetCurrentAspectRatio() const
416 {
417   // node is being used in a separate thread; copy the value from the previous update
418   return GetCameraSceneObject().GetAspectRatio(GetEventThreadServices().GetEventBufferIndex());
419 }
420
421 void CameraActor::SetNearClippingPlane(float nearClippingPlane)
422 {
423   mPropertyChanged = true;
424   if(!Equals(nearClippingPlane, mNearClippingPlane))
425   {
426     mNearClippingPlane = nearClippingPlane;
427
428     // sceneObject is being used in a separate thread; queue a message to set
429     SetNearClippingPlaneMessage(GetEventThreadServices(), GetCameraSceneObject(), mNearClippingPlane);
430   }
431 }
432
433 float CameraActor::GetNearClippingPlane() const
434 {
435   return mNearClippingPlane;
436 }
437
438 void CameraActor::SetFarClippingPlane(float farClippingPlane)
439 {
440   mPropertyChanged = true;
441   if(!Equals(farClippingPlane, mFarClippingPlane))
442   {
443     mFarClippingPlane = farClippingPlane;
444
445     // sceneObject is being used in a separate thread; queue a message to set
446     SetFarClippingPlaneMessage(GetEventThreadServices(), GetCameraSceneObject(), mFarClippingPlane);
447   }
448 }
449
450 float CameraActor::GetFarClippingPlane() const
451 {
452   return mFarClippingPlane;
453 }
454
455 void CameraActor::SetInvertYAxis(bool invertYAxis)
456 {
457   if(invertYAxis != mInvertYAxis)
458   {
459     mInvertYAxis = invertYAxis;
460
461     // sceneObject is being used in a separate thread; queue a message to set
462     SetInvertYAxisMessage(GetEventThreadServices(), GetCameraSceneObject(), mInvertYAxis);
463   }
464 }
465
466 bool CameraActor::GetInvertYAxis() const
467 {
468   return mInvertYAxis;
469 }
470
471 void CameraActor::SetPerspectiveProjection(const Size& size)
472 {
473   SetProjectionMode(Dali::Camera::PERSPECTIVE_PROJECTION);
474   mCanvasSize = static_cast<const Vector2>(size);
475
476   if((size.width < Math::MACHINE_EPSILON_1000) || (size.height < Math::MACHINE_EPSILON_1000))
477   {
478     // If the size given is invalid, i.e. ZERO, then check if we've been added to a scene
479     if(OnScene())
480     {
481       // We've been added to a scene already, set the canvas size to the scene's size
482       mCanvasSize = GetScene().GetSize();
483     }
484     else
485     {
486       // We've not been added to a scene yet, so just return.
487       // We'll set the canvas size when we get added to a scene later
488       return;
489     }
490   }
491   ApplyDefaultProjection();
492 }
493
494 void CameraActor::SetOrthographicProjection(const Size& size)
495 {
496   SetProjectionMode(Dali::Camera::ORTHOGRAPHIC_PROJECTION);
497   mCanvasSize = static_cast<const Vector2>(size);
498
499   if((size.width < Math::MACHINE_EPSILON_1000) || (size.height < Math::MACHINE_EPSILON_1000))
500   {
501     // If the size given is invalid, i.e. ZERO, then check if we've been added to a scene
502     if(OnScene())
503     {
504       // We've been added to a scene already, set the canvas size to the scene's size
505       mCanvasSize = GetScene().GetSize();
506     }
507     else
508     {
509       // We've not been added to a scene yet, so just return.
510       // We'll set the canvas size when we get added to a scene later
511       return;
512     }
513   }
514
515   ApplyDefaultProjection();
516 }
517
518 void CameraActor::ApplyDefaultProjection()
519 {
520   const float width  = mCanvasSize.width;
521   const float height = mCanvasSize.height;
522
523   // Choose near, far and Z parameters to match the SetPerspectiveProjection above.
524   float nearClippingPlane;
525   float farClippingPlane;
526   float cameraZ;
527   CalculateClippingAndZ(width, height, nearClippingPlane, farClippingPlane, cameraZ);
528
529   // calculate orthographic size.
530   const float orthographicSize = (mProjectionDirection == DevelCameraActor::ProjectionDirection::VERTICAL ? height : width) * 0.5f;
531
532   // calculate the position of the camera to have the desired aspect ratio
533   const float fieldOfView = 2.0f * std::atan(orthographicSize / cameraZ);
534
535   // unless it is too small, we want at least as much space to the back as we have torwards the front
536   const float minClippingFarPlane = 2.f * nearClippingPlane;
537   if(farClippingPlane < minClippingFarPlane)
538   {
539     farClippingPlane = minClippingFarPlane;
540   }
541
542   const float aspectRatio = width / height;
543
544   // sceneObject is being used in a separate thread; queue a message to set
545   SetFieldOfView(fieldOfView);
546   SetNearClippingPlane(nearClippingPlane);
547   SetFarClippingPlane(farClippingPlane);
548   SetAspectRatio(aspectRatio);
549   SetOrthographicSize(orthographicSize);
550   SetZ(cameraZ);
551 }
552
553 bool CameraActor::BuildPickingRay(const Vector2&  screenCoordinates,
554                                   const Viewport& viewport,
555                                   Vector4&        rayOrigin,
556                                   Vector4&        rayDirection)
557 {
558   bool success = true;
559   if(mProjectionMode == Dali::Camera::PERSPECTIVE_PROJECTION)
560   {
561     // Build a picking ray in the world reference system.
562     // ray starts from the camera world position
563     rayOrigin   = GetNode().GetWorldMatrix(0).GetTranslation();
564     rayOrigin.w = 1.0f;
565
566     // Transform the touch point from the screen coordinate system to the world coordinates system.
567     Vector4       near(screenCoordinates.x - static_cast<float>(viewport.x),
568                  static_cast<float>(viewport.height) - (screenCoordinates.y - static_cast<float>(viewport.y)),
569                  0.f,
570                  1.f);
571     const Matrix& inverseViewProjection = GetCameraSceneObject().GetInverseViewProjectionMatrix(GetEventThreadServices().GetEventBufferIndex());
572     success                             = Unproject(near, inverseViewProjection, static_cast<float>(viewport.width), static_cast<float>(viewport.height), near);
573
574     // Compute the ray's director vector.
575     rayDirection.x = near.x - rayOrigin.x;
576     rayDirection.y = near.y - rayOrigin.y;
577     rayDirection.z = near.z - rayOrigin.z;
578     rayDirection.Normalize();
579     rayDirection.w = 1.f;
580   }
581   else
582   {
583     float nearPlaneDistance = GetNearClippingPlane();
584     BuildOrthoPickingRay(GetViewMatrix(),
585                          GetProjectionMatrix(),
586                          viewport,
587                          screenCoordinates.x,
588                          screenCoordinates.y,
589                          rayOrigin,
590                          rayDirection,
591                          nearPlaneDistance);
592   }
593
594   return success;
595 }
596
597 const Matrix& CameraActor::GetViewMatrix() const
598 {
599   if(OnScene())
600   {
601     return GetCameraSceneObject().GetViewMatrix(GetEventThreadServices().GetEventBufferIndex());
602   }
603   else
604   {
605     return Matrix::IDENTITY;
606   }
607 }
608
609 const Matrix& CameraActor::GetProjectionMatrix() const
610 {
611   if(OnScene())
612   {
613     return GetCameraSceneObject().GetProjectionMatrix(GetEventThreadServices().GetEventBufferIndex());
614   }
615   else
616   {
617     return Matrix::IDENTITY;
618   }
619 }
620 const SceneGraph::Camera& CameraActor::GetCameraSceneObject() const
621 {
622   return static_cast<const SceneGraph::Camera&>(GetNode());
623 }
624
625 void CameraActor::RotateProjection(int rotationAngle)
626 {
627   // sceneObject is being used in a separate thread; queue a message to set
628   RotateProjectionMessage(GetEventThreadServices(), GetCameraSceneObject(), rotationAngle);
629 }
630
631 void CameraActor::SetDefaultProperty(Property::Index index, const Property::Value& propertyValue)
632 {
633   if(index < DEFAULT_ACTOR_PROPERTY_MAX_COUNT)
634   {
635     Actor::SetDefaultProperty(index, propertyValue);
636   }
637   else
638   {
639     switch(index)
640     {
641       case Dali::CameraActor::Property::TYPE:
642       {
643         Dali::Camera::Type cameraType = Dali::Camera::Type(propertyValue.Get<int>());
644         SetType(cameraType);
645         break;
646       }
647       case Dali::CameraActor::Property::PROJECTION_MODE:
648       {
649         Dali::Camera::ProjectionMode projectionMode = Dali::Camera::ProjectionMode(propertyValue.Get<int>());
650         SetProjectionMode(projectionMode);
651         break;
652       }
653       case Dali::CameraActor::Property::FIELD_OF_VIEW:
654       {
655         SetFieldOfView(propertyValue.Get<float>()); // set to 0 in case property is not float
656         break;
657       }
658       case Dali::DevelCameraActor::Property::ORTHOGRAPHIC_SIZE:
659       {
660         SetOrthographicSize(propertyValue.Get<float>()); // set to 0 in case property is not float
661         break;
662       }
663       case Dali::CameraActor::Property::ASPECT_RATIO:
664       {
665         SetAspectRatio(propertyValue.Get<float>()); // set to 0 in case property is not float
666         break;
667       }
668       case Dali::CameraActor::Property::NEAR_PLANE_DISTANCE:
669       {
670         SetNearClippingPlane(propertyValue.Get<float>()); // set to 0 in case property is not float
671         break;
672       }
673       case Dali::CameraActor::Property::FAR_PLANE_DISTANCE:
674       {
675         SetFarClippingPlane(propertyValue.Get<float>()); // set to 0 in case property is not float
676         break;
677       }
678       case Dali::CameraActor::Property::LEFT_PLANE_DISTANCE:
679       {
680         DALI_LOG_WARNING("LEFT_PLANE_DISTANCE is read-only\n");
681         break;
682       }
683       case Dali::CameraActor::Property::RIGHT_PLANE_DISTANCE:
684       {
685         DALI_LOG_WARNING("RIGHT_PLANE_DISTANCE is read-only\n");
686         break;
687       }
688       case Dali::CameraActor::Property::TOP_PLANE_DISTANCE:
689       {
690         DALI_LOG_WARNING("TOP_PLANE_DISTANCE is read-only\n");
691         break;
692       }
693       case Dali::CameraActor::Property::BOTTOM_PLANE_DISTANCE:
694       {
695         DALI_LOG_WARNING("BOTTOM_PLANE_DISTANCE is read-only\n");
696         break;
697       }
698       case Dali::CameraActor::Property::TARGET_POSITION:
699       {
700         SetTarget(propertyValue.Get<Vector3>()); // set to 0 in case property is not Vector3
701         break;
702       }
703       case Dali::CameraActor::Property::PROJECTION_MATRIX:
704       {
705         DALI_LOG_WARNING("projection-matrix is read-only\n");
706         break;
707       }
708       case Dali::CameraActor::Property::VIEW_MATRIX:
709       {
710         DALI_LOG_WARNING("view-matrix is read-only\n");
711         break;
712       }
713       case Dali::CameraActor::Property::INVERT_Y_AXIS:
714       {
715         SetInvertYAxis(propertyValue.Get<bool>()); // set to false in case property is not bool
716         break;
717       }
718       case Dali::DevelCameraActor::Property::REFLECTION_PLANE:
719       {
720         SetReflectByPlane(propertyValue.Get<Vector4>());
721         break;
722       }
723       case Dali::DevelCameraActor::Property::PROJECTION_DIRECTION:
724       {
725         Dali::DevelCameraActor::ProjectionDirection projectionDirection = Dali::DevelCameraActor::ProjectionDirection(propertyValue.Get<int>());
726         SetProjectionDirection(projectionDirection);
727         break;
728       }
729
730       default:
731       {
732         DALI_LOG_WARNING("Unknown property (%d)\n", index);
733         break;
734       }
735     } // switch(index)
736
737   } // else
738 }
739
740 Property::Value CameraActor::GetDefaultProperty(Property::Index index) const
741 {
742   Property::Value ret;
743   if(index < DEFAULT_ACTOR_PROPERTY_MAX_COUNT)
744   {
745     ret = Actor::GetDefaultProperty(index);
746   }
747   else
748   {
749     switch(index)
750     {
751       case Dali::CameraActor::Property::TYPE:
752       {
753         ret = mType;
754         break;
755       }
756       case Dali::CameraActor::Property::PROJECTION_MODE:
757       {
758         ret = mProjectionMode;
759         break;
760       }
761       case Dali::CameraActor::Property::FIELD_OF_VIEW:
762       {
763         ret = mFieldOfView;
764         break;
765       }
766       case Dali::DevelCameraActor::Property::ORTHOGRAPHIC_SIZE:
767       {
768         ret = mOrthographicSize;
769         break;
770       }
771       case Dali::CameraActor::Property::ASPECT_RATIO:
772       {
773         ret = mAspectRatio;
774         break;
775       }
776       case Dali::CameraActor::Property::NEAR_PLANE_DISTANCE:
777       {
778         ret = mNearClippingPlane;
779         break;
780       }
781       case Dali::CameraActor::Property::FAR_PLANE_DISTANCE:
782       {
783         ret = mFarClippingPlane;
784         break;
785       }
786       case Dali::CameraActor::Property::LEFT_PLANE_DISTANCE:
787       {
788         ret = OrthographicSizeConverter(mOrthographicSize, mAspectRatio, mProjectionDirection).LeftPlaneDistance();
789         break;
790       }
791       case Dali::CameraActor::Property::RIGHT_PLANE_DISTANCE:
792       {
793         ret = OrthographicSizeConverter(mOrthographicSize, mAspectRatio, mProjectionDirection).RightPlaneDistance();
794         break;
795       }
796       case Dali::CameraActor::Property::TOP_PLANE_DISTANCE:
797       {
798         ret = OrthographicSizeConverter(mOrthographicSize, mAspectRatio, mProjectionDirection).TopPlaneDistance();
799         break;
800       }
801       case Dali::CameraActor::Property::BOTTOM_PLANE_DISTANCE:
802       {
803         ret = OrthographicSizeConverter(mOrthographicSize, mAspectRatio, mProjectionDirection).BottomPlaneDistance();
804         break;
805       }
806       case Dali::CameraActor::Property::TARGET_POSITION:
807       {
808         ret = mTarget;
809         break;
810       }
811       case Dali::CameraActor::Property::PROJECTION_MATRIX:
812       {
813         ret = GetProjectionMatrix(); // Only on scene-graph
814         break;
815       }
816       case Dali::CameraActor::Property::VIEW_MATRIX:
817       {
818         ret = GetViewMatrix(); // Only on scene-graph
819         break;
820       }
821       case Dali::CameraActor::Property::INVERT_Y_AXIS:
822       {
823         ret = mInvertYAxis;
824         break;
825       }
826       case Dali::DevelCameraActor::Property::PROJECTION_DIRECTION:
827       {
828         ret = mProjectionDirection;
829         break;
830       }
831     } // switch(index)
832   }
833
834   return ret;
835 }
836
837 Property::Value CameraActor::GetDefaultPropertyCurrentValue(Property::Index index) const
838 {
839   Property::Value ret;
840   if(index < DEFAULT_ACTOR_PROPERTY_MAX_COUNT)
841   {
842     ret = Actor::GetDefaultPropertyCurrentValue(index);
843   }
844   else
845   {
846     switch(index)
847     {
848       case Dali::CameraActor::Property::FIELD_OF_VIEW:
849       {
850         ret = GetCurrentFieldOfView();
851         break;
852       }
853       case Dali::DevelCameraActor::Property::ORTHOGRAPHIC_SIZE:
854       {
855         ret = GetCurrentOrthographicSize();
856         break;
857       }
858       case Dali::CameraActor::Property::ASPECT_RATIO:
859       {
860         ret = GetCurrentAspectRatio();
861         break;
862       }
863       case Dali::CameraActor::Property::LEFT_PLANE_DISTANCE:
864       {
865         ret = OrthographicSizeConverter(GetCurrentOrthographicSize(), GetCurrentAspectRatio(), mProjectionDirection).LeftPlaneDistance();
866         break;
867       }
868       case Dali::CameraActor::Property::RIGHT_PLANE_DISTANCE:
869       {
870         ret = OrthographicSizeConverter(GetCurrentOrthographicSize(), GetCurrentAspectRatio(), mProjectionDirection).RightPlaneDistance();
871         break;
872       }
873       case Dali::CameraActor::Property::TOP_PLANE_DISTANCE:
874       {
875         ret = OrthographicSizeConverter(GetCurrentOrthographicSize(), GetCurrentAspectRatio(), mProjectionDirection).TopPlaneDistance();
876         break;
877       }
878       case Dali::CameraActor::Property::BOTTOM_PLANE_DISTANCE:
879       {
880         ret = OrthographicSizeConverter(GetCurrentOrthographicSize(), GetCurrentAspectRatio(), mProjectionDirection).BottomPlaneDistance();
881         break;
882       }
883       default:
884       {
885         ret = GetDefaultProperty(index); // Most are event-side properties, the scene-graph properties are only on the scene-graph
886       }
887     } // switch(index)
888   }
889
890   return ret;
891 }
892
893 void CameraActor::OnNotifyDefaultPropertyAnimation(Animation& animation, Property::Index index, const Property::Value& value, Animation::Type animationType)
894 {
895   if(index < DEFAULT_ACTOR_PROPERTY_MAX_COUNT)
896   {
897     Actor::OnNotifyDefaultPropertyAnimation(animation, index, value, animationType);
898   }
899   else
900   {
901     switch(animationType)
902     {
903       case Animation::TO:
904       case Animation::BETWEEN:
905       {
906         switch(index)
907         {
908           case Dali::CameraActor::Property::FIELD_OF_VIEW:
909           {
910             value.Get(mFieldOfView);
911             break;
912           }
913           case Dali::DevelCameraActor::Property::ORTHOGRAPHIC_SIZE:
914           {
915             value.Get(mOrthographicSize);
916             break;
917           }
918           case Dali::CameraActor::Property::ASPECT_RATIO:
919           {
920             value.Get(mAspectRatio);
921             break;
922           }
923         }
924         break;
925       }
926       case Animation::BY:
927       {
928         switch(index)
929         {
930           case Dali::CameraActor::Property::FIELD_OF_VIEW:
931           {
932             AdjustValue<float>(mFieldOfView, value);
933             break;
934           }
935           case Dali::DevelCameraActor::Property::ORTHOGRAPHIC_SIZE:
936           {
937             AdjustValue<float>(mOrthographicSize, value);
938             break;
939           }
940           case Dali::CameraActor::Property::ASPECT_RATIO:
941           {
942             AdjustValue<float>(mAspectRatio, value);
943             break;
944           }
945         }
946         break;
947       }
948     }
949   }
950 }
951
952 const SceneGraph::PropertyBase* CameraActor::GetSceneObjectAnimatableProperty(Property::Index index) const
953 {
954   const SceneGraph::PropertyBase* property(nullptr);
955   switch(index)
956   {
957     case Dali::CameraActor::Property::FIELD_OF_VIEW:
958     {
959       property = GetCameraSceneObject().GetFieldOfView();
960       break;
961     }
962     case Dali::DevelCameraActor::Property::ORTHOGRAPHIC_SIZE:
963     {
964       property = GetCameraSceneObject().GetOrthographicSize();
965       break;
966     }
967     case Dali::CameraActor::Property::ASPECT_RATIO:
968     {
969       property = GetCameraSceneObject().GetAspectRatio();
970       break;
971     }
972       // no default on purpose as we chain method up to actor
973   }
974   if(!property)
975   {
976     // not our property, ask base
977     property = Actor::GetSceneObjectAnimatableProperty(index);
978   }
979
980   return property;
981 }
982
983 const PropertyInputImpl* CameraActor::GetSceneObjectInputProperty(Property::Index index) const
984 {
985   const PropertyInputImpl* property(nullptr);
986
987   switch(index)
988   {
989     case Dali::CameraActor::Property::FIELD_OF_VIEW:
990     {
991       property = GetCameraSceneObject().GetFieldOfView();
992       break;
993     }
994     case Dali::DevelCameraActor::Property::ORTHOGRAPHIC_SIZE:
995     {
996       property = GetCameraSceneObject().GetOrthographicSize();
997       break;
998     }
999     case Dali::CameraActor::Property::ASPECT_RATIO:
1000     {
1001       property = GetCameraSceneObject().GetAspectRatio();
1002       break;
1003     }
1004     case Dali::CameraActor::Property::PROJECTION_MATRIX:
1005     {
1006       property = GetCameraSceneObject().GetProjectionMatrix();
1007       break;
1008     }
1009     case Dali::CameraActor::Property::VIEW_MATRIX:
1010     {
1011       property = GetCameraSceneObject().GetViewMatrix();
1012       break;
1013     }
1014       // no default on purpose as we chain method up to actor
1015   }
1016   if(!property)
1017   {
1018     property = Actor::GetSceneObjectInputProperty(index);
1019   }
1020
1021   return property;
1022 }
1023
1024 void CameraActor::OnPropertySet(Property::Index index, const Property::Value& propertyValue)
1025 {
1026   // If Position or Orientation are explicitly set, make mPropertyChanged flag true.
1027   if(index == Dali::Actor::Property::POSITION ||
1028      index == Dali::Actor::Property::POSITION_X ||
1029      index == Dali::Actor::Property::POSITION_Y ||
1030      index == Dali::Actor::Property::POSITION_Z ||
1031      index == Dali::Actor::Property::ORIENTATION)
1032   {
1033     mPropertyChanged = true;
1034   }
1035 }
1036
1037 } // namespace Internal
1038
1039 } // namespace Dali