[dali_2.3.33] Merge branch 'devel/master'
[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,    true,    true,   Dali::CameraActor::Property::NEAR_PLANE_DISTANCE       )
57 DALI_PROPERTY( "farPlaneDistance",       FLOAT,    true,    true,    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     BakeNearClippingPlaneMessage(GetEventThreadServices(), GetCameraSceneObject(), mNearClippingPlane);
430   }
431 }
432
433 float CameraActor::GetNearClippingPlane() const
434 {
435   return mNearClippingPlane;
436 }
437
438 float CameraActor::GetCurrentNearClippingPlane() const
439 {
440   return GetCameraSceneObject().GetNearClippingPlane(GetEventThreadServices().GetEventBufferIndex());
441 }
442
443 void CameraActor::SetFarClippingPlane(float farClippingPlane)
444 {
445   mPropertyChanged = true;
446   if(!Equals(farClippingPlane, mFarClippingPlane))
447   {
448     mFarClippingPlane = farClippingPlane;
449
450     // sceneObject is being used in a separate thread; queue a message to set
451     BakeFarClippingPlaneMessage(GetEventThreadServices(), GetCameraSceneObject(), mFarClippingPlane);
452   }
453 }
454
455 float CameraActor::GetFarClippingPlane() const
456 {
457   return mFarClippingPlane;
458 }
459
460 float CameraActor::GetCurrentFarClippingPlane() const
461 {
462   return GetCameraSceneObject().GetFarClippingPlane(GetEventThreadServices().GetEventBufferIndex());
463 }
464
465 void CameraActor::SetInvertYAxis(bool invertYAxis)
466 {
467   if(invertYAxis != mInvertYAxis)
468   {
469     mInvertYAxis = invertYAxis;
470
471     // sceneObject is being used in a separate thread; queue a message to set
472     SetInvertYAxisMessage(GetEventThreadServices(), GetCameraSceneObject(), mInvertYAxis);
473   }
474 }
475
476 bool CameraActor::GetInvertYAxis() const
477 {
478   return mInvertYAxis;
479 }
480
481 void CameraActor::SetPerspectiveProjection(const Size& size)
482 {
483   SetProjectionMode(Dali::Camera::PERSPECTIVE_PROJECTION);
484   mCanvasSize = static_cast<const Vector2>(size);
485
486   if((size.width < Math::MACHINE_EPSILON_1000) || (size.height < Math::MACHINE_EPSILON_1000))
487   {
488     // If the size given is invalid, i.e. ZERO, then check if we've been added to a scene
489     if(OnScene())
490     {
491       // We've been added to a scene already, set the canvas size to the scene's size
492       mCanvasSize = GetScene().GetSize();
493     }
494     else
495     {
496       // We've not been added to a scene yet, so just return.
497       // We'll set the canvas size when we get added to a scene later
498       return;
499     }
500   }
501   ApplyDefaultProjection();
502 }
503
504 void CameraActor::SetOrthographicProjection(const Size& size)
505 {
506   SetProjectionMode(Dali::Camera::ORTHOGRAPHIC_PROJECTION);
507   mCanvasSize = static_cast<const Vector2>(size);
508
509   if((size.width < Math::MACHINE_EPSILON_1000) || (size.height < Math::MACHINE_EPSILON_1000))
510   {
511     // If the size given is invalid, i.e. ZERO, then check if we've been added to a scene
512     if(OnScene())
513     {
514       // We've been added to a scene already, set the canvas size to the scene's size
515       mCanvasSize = GetScene().GetSize();
516     }
517     else
518     {
519       // We've not been added to a scene yet, so just return.
520       // We'll set the canvas size when we get added to a scene later
521       return;
522     }
523   }
524
525   ApplyDefaultProjection();
526 }
527
528 void CameraActor::ApplyDefaultProjection()
529 {
530   const float width  = mCanvasSize.width;
531   const float height = mCanvasSize.height;
532
533   // Choose near, far and Z parameters to match the SetPerspectiveProjection above.
534   float nearClippingPlane;
535   float farClippingPlane;
536   float cameraZ;
537   CalculateClippingAndZ(width, height, nearClippingPlane, farClippingPlane, cameraZ);
538
539   // calculate orthographic size.
540   const float orthographicSize = (mProjectionDirection == DevelCameraActor::ProjectionDirection::VERTICAL ? height : width) * 0.5f;
541
542   // calculate the position of the camera to have the desired aspect ratio
543   const float fieldOfView = 2.0f * std::atan(orthographicSize / cameraZ);
544
545   // unless it is too small, we want at least as much space to the back as we have torwards the front
546   const float minClippingFarPlane = 2.f * nearClippingPlane;
547   if(farClippingPlane < minClippingFarPlane)
548   {
549     farClippingPlane = minClippingFarPlane;
550   }
551
552   const float aspectRatio = width / height;
553
554   // sceneObject is being used in a separate thread; queue a message to set
555   SetFieldOfView(fieldOfView);
556   SetNearClippingPlane(nearClippingPlane);
557   SetFarClippingPlane(farClippingPlane);
558   SetAspectRatio(aspectRatio);
559   SetOrthographicSize(orthographicSize);
560   SetZ(cameraZ);
561 }
562
563 bool CameraActor::BuildPickingRay(const Vector2&  screenCoordinates,
564                                   const Viewport& viewport,
565                                   Vector4&        rayOrigin,
566                                   Vector4&        rayDirection)
567 {
568   bool success = true;
569   if(mProjectionMode == Dali::Camera::PERSPECTIVE_PROJECTION)
570   {
571     // Build a picking ray in the world reference system.
572     // ray starts from the camera world position
573     rayOrigin   = GetNode().GetWorldMatrix(0).GetTranslation();
574     rayOrigin.w = 1.0f;
575
576     // Transform the touch point from the screen coordinate system to the world coordinates system.
577     Vector4       near(screenCoordinates.x - static_cast<float>(viewport.x),
578                  static_cast<float>(viewport.height) - (screenCoordinates.y - static_cast<float>(viewport.y)),
579                  0.f,
580                  1.f);
581     const Matrix& inverseViewProjection = GetCameraSceneObject().GetInverseViewProjectionMatrix(GetEventThreadServices().GetEventBufferIndex());
582     success                             = Unproject(near, inverseViewProjection, static_cast<float>(viewport.width), static_cast<float>(viewport.height), near);
583
584     // Compute the ray's director vector.
585     rayDirection.x = near.x - rayOrigin.x;
586     rayDirection.y = near.y - rayOrigin.y;
587     rayDirection.z = near.z - rayOrigin.z;
588     rayDirection.Normalize();
589     rayDirection.w = 1.f;
590   }
591   else
592   {
593     float nearPlaneDistance = GetNearClippingPlane();
594     BuildOrthoPickingRay(GetViewMatrix(),
595                          GetProjectionMatrix(),
596                          viewport,
597                          screenCoordinates.x,
598                          screenCoordinates.y,
599                          rayOrigin,
600                          rayDirection,
601                          nearPlaneDistance);
602   }
603
604   return success;
605 }
606
607 const Matrix& CameraActor::GetViewMatrix() const
608 {
609   if(OnScene())
610   {
611     return GetCameraSceneObject().GetViewMatrix(GetEventThreadServices().GetEventBufferIndex());
612   }
613   else
614   {
615     return Matrix::IDENTITY;
616   }
617 }
618
619 const Matrix& CameraActor::GetProjectionMatrix() const
620 {
621   if(OnScene())
622   {
623     return GetCameraSceneObject().GetProjectionMatrix(GetEventThreadServices().GetEventBufferIndex());
624   }
625   else
626   {
627     return Matrix::IDENTITY;
628   }
629 }
630 const SceneGraph::Camera& CameraActor::GetCameraSceneObject() const
631 {
632   return static_cast<const SceneGraph::Camera&>(GetNode());
633 }
634
635 void CameraActor::RotateProjection(int rotationAngle)
636 {
637   // sceneObject is being used in a separate thread; queue a message to set
638   RotateProjectionMessage(GetEventThreadServices(), GetCameraSceneObject(), rotationAngle);
639 }
640
641 void CameraActor::SetDefaultProperty(Property::Index index, const Property::Value& propertyValue)
642 {
643   if(index < DEFAULT_ACTOR_PROPERTY_MAX_COUNT)
644   {
645     Actor::SetDefaultProperty(index, propertyValue);
646   }
647   else
648   {
649     switch(index)
650     {
651       case Dali::CameraActor::Property::TYPE:
652       {
653         Dali::Camera::Type cameraType = Dali::Camera::Type(propertyValue.Get<int>());
654         SetType(cameraType);
655         break;
656       }
657       case Dali::CameraActor::Property::PROJECTION_MODE:
658       {
659         Dali::Camera::ProjectionMode projectionMode = Dali::Camera::ProjectionMode(propertyValue.Get<int>());
660         SetProjectionMode(projectionMode);
661         break;
662       }
663       case Dali::CameraActor::Property::FIELD_OF_VIEW:
664       {
665         SetFieldOfView(propertyValue.Get<float>()); // set to 0 in case property is not float
666         break;
667       }
668       case Dali::DevelCameraActor::Property::ORTHOGRAPHIC_SIZE:
669       {
670         SetOrthographicSize(propertyValue.Get<float>()); // set to 0 in case property is not float
671         break;
672       }
673       case Dali::CameraActor::Property::ASPECT_RATIO:
674       {
675         SetAspectRatio(propertyValue.Get<float>()); // set to 0 in case property is not float
676         break;
677       }
678       case Dali::CameraActor::Property::NEAR_PLANE_DISTANCE:
679       {
680         SetNearClippingPlane(propertyValue.Get<float>()); // set to 0 in case property is not float
681         break;
682       }
683       case Dali::CameraActor::Property::FAR_PLANE_DISTANCE:
684       {
685         SetFarClippingPlane(propertyValue.Get<float>()); // set to 0 in case property is not float
686         break;
687       }
688       case Dali::CameraActor::Property::LEFT_PLANE_DISTANCE:
689       {
690         DALI_LOG_WARNING("LEFT_PLANE_DISTANCE is read-only\n");
691         break;
692       }
693       case Dali::CameraActor::Property::RIGHT_PLANE_DISTANCE:
694       {
695         DALI_LOG_WARNING("RIGHT_PLANE_DISTANCE is read-only\n");
696         break;
697       }
698       case Dali::CameraActor::Property::TOP_PLANE_DISTANCE:
699       {
700         DALI_LOG_WARNING("TOP_PLANE_DISTANCE is read-only\n");
701         break;
702       }
703       case Dali::CameraActor::Property::BOTTOM_PLANE_DISTANCE:
704       {
705         DALI_LOG_WARNING("BOTTOM_PLANE_DISTANCE is read-only\n");
706         break;
707       }
708       case Dali::CameraActor::Property::TARGET_POSITION:
709       {
710         SetTarget(propertyValue.Get<Vector3>()); // set to 0 in case property is not Vector3
711         break;
712       }
713       case Dali::CameraActor::Property::PROJECTION_MATRIX:
714       {
715         DALI_LOG_WARNING("projection-matrix is read-only\n");
716         break;
717       }
718       case Dali::CameraActor::Property::VIEW_MATRIX:
719       {
720         DALI_LOG_WARNING("view-matrix is read-only\n");
721         break;
722       }
723       case Dali::CameraActor::Property::INVERT_Y_AXIS:
724       {
725         SetInvertYAxis(propertyValue.Get<bool>()); // set to false in case property is not bool
726         break;
727       }
728       case Dali::DevelCameraActor::Property::REFLECTION_PLANE:
729       {
730         SetReflectByPlane(propertyValue.Get<Vector4>());
731         break;
732       }
733       case Dali::DevelCameraActor::Property::PROJECTION_DIRECTION:
734       {
735         Dali::DevelCameraActor::ProjectionDirection projectionDirection = Dali::DevelCameraActor::ProjectionDirection(propertyValue.Get<int>());
736         SetProjectionDirection(projectionDirection);
737         break;
738       }
739
740       default:
741       {
742         DALI_LOG_WARNING("Unknown property (%d)\n", index);
743         break;
744       }
745     } // switch(index)
746
747   } // else
748 }
749
750 Property::Value CameraActor::GetDefaultProperty(Property::Index index) const
751 {
752   Property::Value ret;
753   if(index < DEFAULT_ACTOR_PROPERTY_MAX_COUNT)
754   {
755     ret = Actor::GetDefaultProperty(index);
756   }
757   else
758   {
759     switch(index)
760     {
761       case Dali::CameraActor::Property::TYPE:
762       {
763         ret = mType;
764         break;
765       }
766       case Dali::CameraActor::Property::PROJECTION_MODE:
767       {
768         ret = mProjectionMode;
769         break;
770       }
771       case Dali::CameraActor::Property::FIELD_OF_VIEW:
772       {
773         ret = mFieldOfView;
774         break;
775       }
776       case Dali::DevelCameraActor::Property::ORTHOGRAPHIC_SIZE:
777       {
778         ret = mOrthographicSize;
779         break;
780       }
781       case Dali::CameraActor::Property::ASPECT_RATIO:
782       {
783         ret = mAspectRatio;
784         break;
785       }
786       case Dali::CameraActor::Property::NEAR_PLANE_DISTANCE:
787       {
788         ret = mNearClippingPlane;
789         break;
790       }
791       case Dali::CameraActor::Property::FAR_PLANE_DISTANCE:
792       {
793         ret = mFarClippingPlane;
794         break;
795       }
796       case Dali::CameraActor::Property::LEFT_PLANE_DISTANCE:
797       {
798         ret = OrthographicSizeConverter(mOrthographicSize, mAspectRatio, mProjectionDirection).LeftPlaneDistance();
799         break;
800       }
801       case Dali::CameraActor::Property::RIGHT_PLANE_DISTANCE:
802       {
803         ret = OrthographicSizeConverter(mOrthographicSize, mAspectRatio, mProjectionDirection).RightPlaneDistance();
804         break;
805       }
806       case Dali::CameraActor::Property::TOP_PLANE_DISTANCE:
807       {
808         ret = OrthographicSizeConverter(mOrthographicSize, mAspectRatio, mProjectionDirection).TopPlaneDistance();
809         break;
810       }
811       case Dali::CameraActor::Property::BOTTOM_PLANE_DISTANCE:
812       {
813         ret = OrthographicSizeConverter(mOrthographicSize, mAspectRatio, mProjectionDirection).BottomPlaneDistance();
814         break;
815       }
816       case Dali::CameraActor::Property::TARGET_POSITION:
817       {
818         ret = mTarget;
819         break;
820       }
821       case Dali::CameraActor::Property::PROJECTION_MATRIX:
822       {
823         ret = GetProjectionMatrix(); // Only on scene-graph
824         break;
825       }
826       case Dali::CameraActor::Property::VIEW_MATRIX:
827       {
828         ret = GetViewMatrix(); // Only on scene-graph
829         break;
830       }
831       case Dali::CameraActor::Property::INVERT_Y_AXIS:
832       {
833         ret = mInvertYAxis;
834         break;
835       }
836       case Dali::DevelCameraActor::Property::PROJECTION_DIRECTION:
837       {
838         ret = mProjectionDirection;
839         break;
840       }
841     } // switch(index)
842   }
843
844   return ret;
845 }
846
847 Property::Value CameraActor::GetDefaultPropertyCurrentValue(Property::Index index) const
848 {
849   Property::Value ret;
850   if(index < DEFAULT_ACTOR_PROPERTY_MAX_COUNT)
851   {
852     ret = Actor::GetDefaultPropertyCurrentValue(index);
853   }
854   else
855   {
856     switch(index)
857     {
858       case Dali::CameraActor::Property::FIELD_OF_VIEW:
859       {
860         ret = GetCurrentFieldOfView();
861         break;
862       }
863       case Dali::DevelCameraActor::Property::ORTHOGRAPHIC_SIZE:
864       {
865         ret = GetCurrentOrthographicSize();
866         break;
867       }
868       case Dali::CameraActor::Property::ASPECT_RATIO:
869       {
870         ret = GetCurrentAspectRatio();
871         break;
872       }
873       case Dali::CameraActor::Property::NEAR_PLANE_DISTANCE:
874       {
875         ret = GetCurrentNearClippingPlane();
876         break;
877       }
878       case Dali::CameraActor::Property::FAR_PLANE_DISTANCE:
879       {
880         ret = GetCurrentFarClippingPlane();
881         break;
882       }
883       case Dali::CameraActor::Property::LEFT_PLANE_DISTANCE:
884       {
885         ret = OrthographicSizeConverter(GetCurrentOrthographicSize(), GetCurrentAspectRatio(), mProjectionDirection).LeftPlaneDistance();
886         break;
887       }
888       case Dali::CameraActor::Property::RIGHT_PLANE_DISTANCE:
889       {
890         ret = OrthographicSizeConverter(GetCurrentOrthographicSize(), GetCurrentAspectRatio(), mProjectionDirection).RightPlaneDistance();
891         break;
892       }
893       case Dali::CameraActor::Property::TOP_PLANE_DISTANCE:
894       {
895         ret = OrthographicSizeConverter(GetCurrentOrthographicSize(), GetCurrentAspectRatio(), mProjectionDirection).TopPlaneDistance();
896         break;
897       }
898       case Dali::CameraActor::Property::BOTTOM_PLANE_DISTANCE:
899       {
900         ret = OrthographicSizeConverter(GetCurrentOrthographicSize(), GetCurrentAspectRatio(), mProjectionDirection).BottomPlaneDistance();
901         break;
902       }
903       default:
904       {
905         ret = GetDefaultProperty(index); // Most are event-side properties, the scene-graph properties are only on the scene-graph
906       }
907     } // switch(index)
908   }
909
910   return ret;
911 }
912
913 void CameraActor::OnNotifyDefaultPropertyAnimation(Animation& animation, Property::Index index, const Property::Value& value, Animation::Type animationType)
914 {
915   if(index < DEFAULT_ACTOR_PROPERTY_MAX_COUNT)
916   {
917     Actor::OnNotifyDefaultPropertyAnimation(animation, index, value, animationType);
918   }
919   else
920   {
921     switch(animationType)
922     {
923       case Animation::TO:
924       case Animation::BETWEEN:
925       {
926         switch(index)
927         {
928           case Dali::CameraActor::Property::FIELD_OF_VIEW:
929           {
930             value.Get(mFieldOfView);
931             break;
932           }
933           case Dali::DevelCameraActor::Property::ORTHOGRAPHIC_SIZE:
934           {
935             value.Get(mOrthographicSize);
936             break;
937           }
938           case Dali::CameraActor::Property::ASPECT_RATIO:
939           {
940             value.Get(mAspectRatio);
941             break;
942           }
943           case Dali::CameraActor::Property::NEAR_PLANE_DISTANCE:
944           {
945             value.Get(mNearClippingPlane);
946             break;
947           }
948           case Dali::CameraActor::Property::FAR_PLANE_DISTANCE:
949           {
950             value.Get(mFarClippingPlane);
951             break;
952           }
953         }
954         break;
955       }
956       case Animation::BY:
957       {
958         switch(index)
959         {
960           case Dali::CameraActor::Property::FIELD_OF_VIEW:
961           {
962             AdjustValue<float>(mFieldOfView, value);
963             break;
964           }
965           case Dali::DevelCameraActor::Property::ORTHOGRAPHIC_SIZE:
966           {
967             AdjustValue<float>(mOrthographicSize, value);
968             break;
969           }
970           case Dali::CameraActor::Property::ASPECT_RATIO:
971           {
972             AdjustValue<float>(mAspectRatio, value);
973             break;
974           }
975           case Dali::CameraActor::Property::NEAR_PLANE_DISTANCE:
976           {
977             AdjustValue<float>(mNearClippingPlane, value);
978             break;
979           }
980           case Dali::CameraActor::Property::FAR_PLANE_DISTANCE:
981           {
982             AdjustValue<float>(mFarClippingPlane, value);
983             break;
984           }
985         }
986         break;
987       }
988     }
989   }
990 }
991
992 const SceneGraph::PropertyBase* CameraActor::GetSceneObjectAnimatableProperty(Property::Index index) const
993 {
994   const SceneGraph::PropertyBase* property(nullptr);
995   switch(index)
996   {
997     case Dali::CameraActor::Property::FIELD_OF_VIEW:
998     {
999       property = GetCameraSceneObject().GetFieldOfView();
1000       break;
1001     }
1002     case Dali::DevelCameraActor::Property::ORTHOGRAPHIC_SIZE:
1003     {
1004       property = GetCameraSceneObject().GetOrthographicSize();
1005       break;
1006     }
1007     case Dali::CameraActor::Property::ASPECT_RATIO:
1008     {
1009       property = GetCameraSceneObject().GetAspectRatio();
1010       break;
1011     }
1012     case Dali::CameraActor::Property::NEAR_PLANE_DISTANCE:
1013     {
1014       property = GetCameraSceneObject().GetNearPlaneDistance();
1015       break;
1016     }
1017     case Dali::CameraActor::Property::FAR_PLANE_DISTANCE:
1018     {
1019       property = GetCameraSceneObject().GetFarPlaneDistance();
1020       break;
1021     }
1022       // no default on purpose as we chain method up to actor
1023   }
1024   if(!property)
1025   {
1026     // not our property, ask base
1027     property = Actor::GetSceneObjectAnimatableProperty(index);
1028   }
1029
1030   return property;
1031 }
1032
1033 const PropertyInputImpl* CameraActor::GetSceneObjectInputProperty(Property::Index index) const
1034 {
1035   const PropertyInputImpl* property(nullptr);
1036
1037   switch(index)
1038   {
1039     case Dali::CameraActor::Property::PROJECTION_MODE:
1040     {
1041       property = GetCameraSceneObject().GetProjectionMode();
1042       break;
1043     }
1044     case Dali::CameraActor::Property::FIELD_OF_VIEW:
1045     {
1046       property = GetCameraSceneObject().GetFieldOfView();
1047       break;
1048     }
1049     case Dali::CameraActor::Property::ASPECT_RATIO:
1050     {
1051       property = GetCameraSceneObject().GetAspectRatio();
1052       break;
1053     }
1054     case Dali::CameraActor::Property::NEAR_PLANE_DISTANCE:
1055     {
1056       property = GetCameraSceneObject().GetNearPlaneDistance();
1057       break;
1058     }
1059     case Dali::CameraActor::Property::FAR_PLANE_DISTANCE:
1060     {
1061       property = GetCameraSceneObject().GetFarPlaneDistance();
1062       break;
1063     }
1064     case Dali::CameraActor::Property::PROJECTION_MATRIX:
1065     {
1066       property = GetCameraSceneObject().GetProjectionMatrix();
1067       break;
1068     }
1069     case Dali::CameraActor::Property::VIEW_MATRIX:
1070     {
1071       property = GetCameraSceneObject().GetViewMatrix();
1072       break;
1073     }
1074     case Dali::CameraActor::Property::INVERT_Y_AXIS:
1075     {
1076       property = GetCameraSceneObject().GetInvertYAxis();
1077       break;
1078     }
1079     case Dali::DevelCameraActor::Property::ORTHOGRAPHIC_SIZE:
1080     {
1081       property = GetCameraSceneObject().GetOrthographicSize();
1082       break;
1083     }
1084     case Dali::DevelCameraActor::Property::PROJECTION_DIRECTION:
1085     {
1086       property = GetCameraSceneObject().GetProjectionDirection();
1087       break;
1088     }
1089       // no default on purpose as we chain method up to actor
1090   }
1091   if(!property)
1092   {
1093     property = Actor::GetSceneObjectInputProperty(index);
1094   }
1095
1096   return property;
1097 }
1098
1099 void CameraActor::OnPropertySet(Property::Index index, const Property::Value& propertyValue)
1100 {
1101   // If Position or Orientation are explicitly set, make mPropertyChanged flag true.
1102   if(index == Dali::Actor::Property::POSITION ||
1103      index == Dali::Actor::Property::POSITION_X ||
1104      index == Dali::Actor::Property::POSITION_Y ||
1105      index == Dali::Actor::Property::POSITION_Z ||
1106      index == Dali::Actor::Property::ORIENTATION)
1107   {
1108     mPropertyChanged = true;
1109   }
1110 }
1111
1112 } // namespace Internal
1113
1114 } // namespace Dali