[Tizen] Create ProjectionDirection property at CameraActor
[platform/core/uifw/dali-core.git] / dali / internal / event / actors / camera-actor-impl.cpp
1 /*
2  * Copyright (c) 2022 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/event/common/projection.h>
28 #include <dali/internal/event/common/property-helper.h>
29 #include <dali/internal/event/common/thread-local-storage.h>
30 #include <dali/public-api/object/type-registry.h>
31
32 #include <dali/internal/update/manager/update-manager.h>
33
34 namespace Dali
35 {
36 namespace Internal
37 {
38 namespace
39 {
40 // Properties
41
42 /**
43  * We want to discourage the use of property strings (minimize string comparisons),
44  * particularly for the default properties.
45  *              Name                     Type   writable animatable constraint-input  enum for index-checking
46  */
47 // clang-format off
48 DALI_PROPERTY_TABLE_BEGIN
49 DALI_PROPERTY( "type",                   INTEGER,  true,    false,   true,   Dali::CameraActor::Property::TYPE                  )
50 DALI_PROPERTY( "projectionMode",         INTEGER,  true,    false,   true,   Dali::CameraActor::Property::PROJECTION_MODE       )
51 DALI_PROPERTY( "fieldOfView",            FLOAT,    true,    false,   true,   Dali::CameraActor::Property::FIELD_OF_VIEW         )
52 DALI_PROPERTY( "aspectRatio",            FLOAT,    true,    false,   true,   Dali::CameraActor::Property::ASPECT_RATIO          )
53 DALI_PROPERTY( "nearPlaneDistance",      FLOAT,    true,    false,   true,   Dali::CameraActor::Property::NEAR_PLANE_DISTANCE   )
54 DALI_PROPERTY( "farPlaneDistance",       FLOAT,    true,    false,   true,   Dali::CameraActor::Property::FAR_PLANE_DISTANCE    )
55 DALI_PROPERTY( "leftPlaneDistance",      FLOAT,    true,    false,   true,   Dali::CameraActor::Property::LEFT_PLANE_DISTANCE   )
56 DALI_PROPERTY( "rightPlaneDistance",     FLOAT,    true,    false,   true,   Dali::CameraActor::Property::RIGHT_PLANE_DISTANCE  )
57 DALI_PROPERTY( "topPlaneDistance",       FLOAT,    true,    false,   true,   Dali::CameraActor::Property::TOP_PLANE_DISTANCE    )
58 DALI_PROPERTY( "bottomPlaneDistance",    FLOAT,    true,    false,   true,   Dali::CameraActor::Property::BOTTOM_PLANE_DISTANCE )
59 DALI_PROPERTY( "targetPosition",         VECTOR3,  true,    false,   true,   Dali::CameraActor::Property::TARGET_POSITION       )
60 DALI_PROPERTY( "projectionMatrix",       MATRIX,   false,   false,   true,   Dali::CameraActor::Property::PROJECTION_MATRIX     )
61 DALI_PROPERTY( "viewMatrix",             MATRIX,   false,   false,   true,   Dali::CameraActor::Property::VIEW_MATRIX           )
62 DALI_PROPERTY( "invertYAxis",            BOOLEAN,  true,    false,   true,   Dali::CameraActor::Property::INVERT_Y_AXIS         )
63 DALI_PROPERTY_TABLE_END( DEFAULT_DERIVED_ACTOR_PROPERTY_START_INDEX, CameraDefaultProperties )
64 // clang-format on
65
66 // calculate the far plane distance for a 16bit depth buffer with 4 bits per unit precision
67 void CalculateClippingAndZ(float width, float height, float& nearClippingPlane, float& farClippingPlane, float& cameraZ)
68 {
69   nearClippingPlane = std::max(width, height);
70   farClippingPlane  = nearClippingPlane + static_cast<float>(0xFFFF >> 4);
71   cameraZ           = 2.0f * nearClippingPlane;
72 }
73
74 BaseHandle Create()
75 {
76   return Dali::CameraActor::New();
77 }
78
79 TypeRegistration mType(typeid(Dali::CameraActor), typeid(Dali::Actor), Create, CameraDefaultProperties);
80
81 /**
82  * Builds the picking ray in the world reference system from an orthographic camera
83  * The ray origin is the screen coordinate in the near plane translated to a parallel
84  * plane at the camera origin. The ray direction is the direction the camera is facing
85  * (i.e. Z=-1 in view space).
86  */
87 void BuildOrthoPickingRay(const Matrix&   viewMatrix,
88                           const Matrix&   projectionMatrix,
89                           const Viewport& viewport,
90                           float           screenX,
91                           float           screenY,
92                           Vector4&        rayOrigin,
93                           Vector4&        rayDir,
94                           float           nearPlaneDistance)
95 {
96   //          inv( modelMatrix )          inv( viewMatrix )    inv( projectionMatrix )           normalize
97   //          <-----------------         <-----------------         <--------------           <-------------
98   //  Local                      World                      Camera                 Normalized                 Screen
99   // reference                  reference                  reference                  clip                  coordinates
100   //  system                     system                     system                 coordinates
101   //          ----------------->         ----------------->         -------------->           ------------->
102   //             modelMatrix                 viewMatrix             projectionMatrix             viewport
103
104   // Transforms the touch point from the screen reference system to the world reference system.
105   Matrix invViewProjection(false); // Don't initialize.
106   Matrix::Multiply(invViewProjection, viewMatrix, projectionMatrix);
107   if(!invViewProjection.Invert())
108   {
109     DALI_ASSERT_DEBUG(false);
110   }
111
112   Vector4 near(screenX - static_cast<float>(viewport.x),
113                static_cast<float>(viewport.height) - (screenY - static_cast<float>(viewport.y)),
114                0.f,
115                1.f);
116   if(!Unproject(near, invViewProjection, static_cast<float>(viewport.width), static_cast<float>(viewport.height), rayOrigin))
117   {
118     DALI_ASSERT_DEBUG(false);
119   }
120
121   Matrix invView = viewMatrix;
122   if(!invView.Invert())
123   {
124     DALI_ASSERT_DEBUG(false);
125   }
126
127   Vector4 cameraOrigin    = invView * Vector4(0.f, 0.f, 0.f, 1.f);
128   Vector4 nearPlaneOrigin = invView * Vector4(0.0f, 0.0f, -nearPlaneDistance, 1.0f);
129
130   // Vector pointing from the camera to the near plane
131   rayDir = cameraOrigin - nearPlaneOrigin;
132   rayOrigin -= rayDir;
133   rayDir.Normalize();
134   rayDir.w = 1.0f;
135 }
136
137 /**
138  * @brief Convert from vertical FoV to horizontal FoV
139  *
140  * @param aspectRatio aspect ratio.
141  * @param verticalFov Vertical field of view by radian.
142  * @return Horizontal field of view by radian.
143  */
144 inline float ConvertFovFromVerticalToHorizontal(float aspectRatio, float verticalFov)
145 {
146   return 2.0f * std::atan(std::tan(verticalFov * 0.5f) * aspectRatio);
147 }
148
149 /**
150  * @brief Convert from horizontal FoV to vertical FoV
151  *
152  * @param aspectRatio aspect ratio.
153  * @param horizontalFov Horizontal field of view by radian.
154  * @return Vertical field of view by radian.
155  */
156 inline float ConvertFovFromHorizontalToVertical(float aspectRatio, float horizontalFov)
157 {
158   return 2.0f * std::atan(std::tan(horizontalFov * 0.5f) / aspectRatio);
159 }
160
161 } // namespace
162
163 CameraActorPtr CameraActor::New(const Size& size)
164 {
165   CameraActorPtr actor(new CameraActor(*CreateNode()));
166
167   // Second-phase construction
168   actor->Initialize();
169
170   actor->SetName("DefaultCamera");
171   actor->SetPerspectiveProjection(size);
172
173   // By default Actors face in the positive Z direction in world space
174   // CameraActors should face in the negative Z direction, towards the other actors
175   actor->SetOrientation(Quaternion(Dali::ANGLE_180, Vector3::YAXIS));
176
177   return actor;
178 }
179
180 CameraActor::CameraActor(const SceneGraph::Node& node)
181 : Actor(Actor::BASIC, node),
182   mSceneObject(nullptr),
183   mTarget(SceneGraph::Camera::DEFAULT_TARGET_POSITION),
184   mType(SceneGraph::Camera::DEFAULT_TYPE),
185   mProjectionMode(SceneGraph::Camera::DEFAULT_MODE),
186   mProjectionDirection(Dali::DevelCameraActor::ProjectionDirection::VERTICAL),
187   mFieldOfView(SceneGraph::Camera::DEFAULT_FIELD_OF_VIEW),
188   mAspectRatio(SceneGraph::Camera::DEFAULT_ASPECT_RATIO),
189   mNearClippingPlane(SceneGraph::Camera::DEFAULT_NEAR_CLIPPING_PLANE),
190   mFarClippingPlane(SceneGraph::Camera::DEFAULT_FAR_CLIPPING_PLANE),
191   mLeftClippingPlane(SceneGraph::Camera::DEFAULT_LEFT_CLIPPING_PLANE),
192   mRightClippingPlane(SceneGraph::Camera::DEFAULT_RIGHT_CLIPPING_PLANE),
193   mTopClippingPlane(SceneGraph::Camera::DEFAULT_TOP_CLIPPING_PLANE),
194   mBottomClippingPlane(SceneGraph::Camera::DEFAULT_BOTTOM_CLIPPING_PLANE),
195   mInvertYAxis(SceneGraph::Camera::DEFAULT_INVERT_Y_AXIS),
196   mPropertyChanged(false)
197 {
198 }
199
200 CameraActor::~CameraActor()
201 {
202   if(EventThreadServices::IsCoreRunning())
203   {
204     // Create scene-object and transfer ownership through message
205     RemoveCameraMessage(GetEventThreadServices().GetUpdateManager(), mSceneObject);
206   }
207 }
208
209 void CameraActor::OnInitialize()
210 {
211   // Create scene-object and keep raw pointer for message passing.
212   SceneGraph::Camera* sceneGraphCamera = SceneGraph::Camera::New();
213
214   // Store a pointer to this camera node inside the scene-graph camera.
215   sceneGraphCamera->SetNode(&GetNode());
216
217   mSceneObject = sceneGraphCamera;
218   OwnerPointer<SceneGraph::Camera> sceneGraphCameraOwner(sceneGraphCamera);
219
220   // Send message to inform update of this camera (and move ownership).
221   AddCameraMessage(GetEventThreadServices().GetUpdateManager(), sceneGraphCameraOwner);
222 }
223
224 void CameraActor::OnSceneConnectionInternal()
225 {
226   // If the canvas size has not been set, then use the size of the scene to which we've been added
227   // in order to set up the current projection
228   if(!mPropertyChanged && ((mCanvasSize.width < Math::MACHINE_EPSILON_1000) || (mCanvasSize.height < Math::MACHINE_EPSILON_1000)))
229   {
230     if(mProjectionMode == Dali::Camera::ORTHOGRAPHIC_PROJECTION)
231     {
232       SetOrthographicProjection(GetScene().GetSize());
233     }
234     else //if(mProjectionMode == Dali::Camera::PERSPECTIVE_PROJECTION)
235     {
236       SetPerspectiveProjection(GetScene().GetSize());
237     }
238   }
239 }
240
241 void CameraActor::SetReflectByPlane(const Vector4& plane)
242 {
243   if(mSceneObject)
244   {
245     SetReflectByPlaneMessage(GetEventThreadServices(), *mSceneObject, plane);
246   }
247 }
248
249 void CameraActor::SetTarget(const Vector3& target)
250 {
251   mPropertyChanged = true;
252   if(target != mTarget) // using range epsilon
253   {
254     mTarget = target;
255
256     SetTargetPositionMessage(GetEventThreadServices(), *mSceneObject, mTarget);
257   }
258 }
259
260 Vector3 CameraActor::GetTarget() const
261 {
262   return mTarget;
263 }
264
265 void CameraActor::SetType(Dali::Camera::Type type)
266 {
267   if(type != mType)
268   {
269     mType = type;
270
271     // sceneObject is being used in a separate thread; queue a message to set
272     SetTypeMessage(GetEventThreadServices(), *mSceneObject, mType);
273   }
274 }
275
276 Dali::Camera::Type CameraActor::GetType() const
277 {
278   return mType;
279 }
280
281 void CameraActor::SetProjectionMode(Dali::Camera::ProjectionMode mode)
282 {
283   if(mode != mProjectionMode)
284   {
285     mProjectionMode = mode;
286
287     // sceneObject is being used in a separate thread; queue a message to set
288     SetProjectionModeMessage(GetEventThreadServices(), *mSceneObject, mProjectionMode);
289   }
290 }
291
292 Dali::Camera::ProjectionMode CameraActor::GetProjectionMode() const
293 {
294   return mProjectionMode;
295 }
296
297 void CameraActor::SetProjectionDirection(Dali::DevelCameraActor::ProjectionDirection direction)
298 {
299   mPropertyChanged = true;
300   if(direction != mProjectionDirection)
301   {
302     mProjectionDirection = direction;
303
304     // Update update side FoV value.
305     float verticalFieldOfView = mFieldOfView;
306     if(DALI_UNLIKELY(mProjectionDirection == DevelCameraActor::HORIZONTAL))
307     {
308       verticalFieldOfView = ConvertFovFromHorizontalToVertical(mAspectRatio, mFieldOfView);
309     }
310
311     // sceneObject is being used in a separate thread; queue a message to set
312     SetFieldOfViewMessage(GetEventThreadServices(), *mSceneObject, verticalFieldOfView);
313   }
314 }
315
316 void CameraActor::SetFieldOfView(float fieldOfView)
317 {
318   mPropertyChanged = true;
319   if(!Equals(fieldOfView, mFieldOfView))
320   {
321     mFieldOfView = fieldOfView;
322
323     float verticalFieldOfView = mFieldOfView;
324     if(DALI_UNLIKELY(mProjectionDirection == DevelCameraActor::HORIZONTAL))
325     {
326       verticalFieldOfView = ConvertFovFromHorizontalToVertical(mAspectRatio, mFieldOfView);
327     }
328
329     // sceneObject is being used in a separate thread; queue a message to set
330     SetFieldOfViewMessage(GetEventThreadServices(), *mSceneObject, verticalFieldOfView);
331   }
332 }
333
334 float CameraActor::GetFieldOfView() const
335 {
336   return mFieldOfView;
337 }
338
339 void CameraActor::SetAspectRatio(float aspectRatio)
340 {
341   mPropertyChanged = true;
342   if(!Equals(aspectRatio, mAspectRatio))
343   {
344     mAspectRatio = aspectRatio;
345
346     // sceneObject is being used in a separate thread; queue a message to set
347     SetAspectRatioMessage(GetEventThreadServices(), *mSceneObject, mAspectRatio);
348
349     if(DALI_UNLIKELY(mProjectionDirection == DevelCameraActor::HORIZONTAL))
350     {
351       float verticalFieldOfView = ConvertFovFromHorizontalToVertical(mAspectRatio, mFieldOfView);
352
353       // sceneObject is being used in a separate thread; queue a message to set
354       SetFieldOfViewMessage(GetEventThreadServices(), *mSceneObject, verticalFieldOfView);
355     }
356   }
357 }
358
359 float CameraActor::GetAspectRatio() const
360 {
361   return mAspectRatio;
362 }
363
364 void CameraActor::SetNearClippingPlane(float nearClippingPlane)
365 {
366   mPropertyChanged = true;
367   if(!Equals(nearClippingPlane, mNearClippingPlane))
368   {
369     mNearClippingPlane = nearClippingPlane;
370
371     // sceneObject is being used in a separate thread; queue a message to set
372     SetNearClippingPlaneMessage(GetEventThreadServices(), *mSceneObject, mNearClippingPlane);
373   }
374 }
375
376 float CameraActor::GetNearClippingPlane() const
377 {
378   return mNearClippingPlane;
379 }
380
381 void CameraActor::SetFarClippingPlane(float farClippingPlane)
382 {
383   mPropertyChanged = true;
384   if(!Equals(farClippingPlane, mFarClippingPlane))
385   {
386     mFarClippingPlane = farClippingPlane;
387
388     // sceneObject is being used in a separate thread; queue a message to set
389     SetFarClippingPlaneMessage(GetEventThreadServices(), *mSceneObject, mFarClippingPlane);
390   }
391 }
392
393 float CameraActor::GetFarClippingPlane() const
394 {
395   return mFarClippingPlane;
396 }
397
398 void CameraActor::SetLeftClippingPlane(float leftClippingPlane)
399 {
400   mPropertyChanged = true;
401   if(!Equals(leftClippingPlane, mLeftClippingPlane))
402   {
403     mLeftClippingPlane = leftClippingPlane;
404
405     // sceneObject is being used in a separate thread; queue a message to set
406     SetLeftClippingPlaneMessage(GetEventThreadServices(), *mSceneObject, mLeftClippingPlane);
407   }
408 }
409
410 void CameraActor::SetRightClippingPlane(float rightClippingPlane)
411 {
412   mPropertyChanged = true;
413   if(!Equals(rightClippingPlane, mRightClippingPlane))
414   {
415     mRightClippingPlane = rightClippingPlane;
416
417     // sceneObject is being used in a separate thread; queue a message to set
418     SetRightClippingPlaneMessage(GetEventThreadServices(), *mSceneObject, mRightClippingPlane);
419   }
420 }
421
422 void CameraActor::SetTopClippingPlane(float topClippingPlane)
423 {
424   mPropertyChanged = true;
425   if(!Equals(topClippingPlane, mTopClippingPlane))
426   {
427     mTopClippingPlane = topClippingPlane;
428
429     // sceneObject is being used in a separate thread; queue a message to set
430     SetTopClippingPlaneMessage(GetEventThreadServices(), *mSceneObject, mTopClippingPlane);
431   }
432 }
433
434 void CameraActor::SetBottomClippingPlane(float bottomClippingPlane)
435 {
436   mPropertyChanged = true;
437   if(!Equals(bottomClippingPlane, mBottomClippingPlane))
438   {
439     mBottomClippingPlane = bottomClippingPlane;
440
441     // sceneObject is being used in a separate thread; queue a message to set
442     SetBottomClippingPlaneMessage(GetEventThreadServices(), *mSceneObject, mBottomClippingPlane);
443   }
444 }
445
446 void CameraActor::SetInvertYAxis(bool invertYAxis)
447 {
448   if(invertYAxis != mInvertYAxis)
449   {
450     mInvertYAxis = invertYAxis;
451
452     // sceneObject is being used in a separate thread; queue a message to set
453     SetInvertYAxisMessage(GetEventThreadServices(), *mSceneObject, mInvertYAxis);
454   }
455 }
456
457 bool CameraActor::GetInvertYAxis() const
458 {
459   return mInvertYAxis;
460 }
461
462 void CameraActor::SetPerspectiveProjection(const Size& size)
463 {
464   SetProjectionMode(Dali::Camera::PERSPECTIVE_PROJECTION);
465   mCanvasSize = size;
466
467   if((size.width < Math::MACHINE_EPSILON_1000) || (size.height < Math::MACHINE_EPSILON_1000))
468   {
469     // If the size given is invalid, i.e. ZERO, then check if we've been added to a scene
470     if(OnScene())
471     {
472       // We've been added to a scene already, set the canvas size to the scene's size
473       mCanvasSize = GetScene().GetSize();
474     }
475     else
476     {
477       // We've not been added to a scene yet, so just return.
478       // We'll set the canvas size when we get added to a scene later
479       return;
480     }
481   }
482
483   float width  = mCanvasSize.width;
484   float height = mCanvasSize.height;
485
486   float nearClippingPlane;
487   float farClippingPlane;
488   float cameraZ;
489   CalculateClippingAndZ(width, height, nearClippingPlane, farClippingPlane, cameraZ);
490
491   // calculate the position of the camera to have the desired aspect ratio
492   const float fieldOfView = 2.0f * std::atan(height * 0.5f / cameraZ);
493
494   // unless it is too small, we want at least as much space to the back as we have torwards the front
495   const float minClippingFarPlane = 2.f * nearClippingPlane;
496   if(farClippingPlane < minClippingFarPlane)
497   {
498     farClippingPlane = minClippingFarPlane;
499   }
500
501   const float aspectRatio = width / height;
502
503   // sceneObject is being used in a separate thread; queue a message to set
504   SetFieldOfView(fieldOfView);
505   SetNearClippingPlane(nearClippingPlane);
506   SetFarClippingPlane(farClippingPlane);
507   SetLeftClippingPlane(width * -0.5f);
508   SetRightClippingPlane(width * 0.5f);
509   SetTopClippingPlane(height * 0.5f);     // Top is +ve to keep consistency with orthographic values
510   SetBottomClippingPlane(height * -0.5f); // Bottom is -ve to keep consistency with orthographic values
511   SetAspectRatio(aspectRatio);
512   SetZ(cameraZ);
513 }
514
515 void CameraActor::SetOrthographicProjection(const Vector2& size)
516 {
517   SetProjectionMode(Dali::Camera::ORTHOGRAPHIC_PROJECTION);
518   mCanvasSize = size;
519
520   if((size.width < Math::MACHINE_EPSILON_1000) || (size.height < Math::MACHINE_EPSILON_1000))
521   {
522     // If the size given is invalid, i.e. ZERO, then check if we've been added to a scene
523     if(OnScene())
524     {
525       // We've been added to a scene already, set the canvas size to the scene's size
526       mCanvasSize = GetScene().GetSize();
527     }
528     else
529     {
530       // We've not been added to a scene yet, so just return.
531       // We'll set the canvas size when we get added to a scene later
532       return;
533     }
534   }
535
536   // Choose near, far and Z parameters to match the SetPerspectiveProjection above.
537   float nearClippingPlane;
538   float farClippingPlane;
539   float cameraZ;
540   CalculateClippingAndZ(size.width, size.height, nearClippingPlane, farClippingPlane, cameraZ);
541   SetOrthographicProjection(-size.x * 0.5f, size.x * 0.5f, size.y * 0.5f, size.y * -0.5f, nearClippingPlane, farClippingPlane);
542   SetZ(cameraZ);
543 }
544
545 void CameraActor::SetOrthographicProjection(float left, float right, float top, float bottom, float near, float far)
546 {
547   SetProjectionMode(Dali::Camera::ORTHOGRAPHIC_PROJECTION);
548   SetLeftClippingPlane(left);
549   SetRightClippingPlane(right);
550   SetTopClippingPlane(top);
551   SetBottomClippingPlane(bottom);
552   SetNearClippingPlane(near);
553   SetFarClippingPlane(far);
554 }
555
556 bool CameraActor::BuildPickingRay(const Vector2&  screenCoordinates,
557                                   const Viewport& viewport,
558                                   Vector4&        rayOrigin,
559                                   Vector4&        rayDirection)
560 {
561   bool success = true;
562   if(mProjectionMode == Dali::Camera::PERSPECTIVE_PROJECTION)
563   {
564     // Build a picking ray in the world reference system.
565     // ray starts from the camera world position
566     rayOrigin   = GetNode().GetWorldMatrix(0).GetTranslation();
567     rayOrigin.w = 1.0f;
568
569     // Transform the touch point from the screen coordinate system to the world coordinates system.
570     Vector4       near(screenCoordinates.x - static_cast<float>(viewport.x),
571                  static_cast<float>(viewport.height) - (screenCoordinates.y - static_cast<float>(viewport.y)),
572                  0.f,
573                  1.f);
574     const Matrix& inverseViewProjection = mSceneObject->GetInverseViewProjectionMatrix(GetEventThreadServices().GetEventBufferIndex());
575     success                             = Unproject(near, inverseViewProjection, static_cast<float>(viewport.width), static_cast<float>(viewport.height), near);
576
577     // Compute the ray's director vector.
578     rayDirection.x = near.x - rayOrigin.x;
579     rayDirection.y = near.y - rayOrigin.y;
580     rayDirection.z = near.z - rayOrigin.z;
581     rayDirection.Normalize();
582     rayDirection.w = 1.f;
583   }
584   else
585   {
586     float nearPlaneDistance = GetNearClippingPlane();
587     BuildOrthoPickingRay(GetViewMatrix(),
588                          GetProjectionMatrix(),
589                          viewport,
590                          screenCoordinates.x,
591                          screenCoordinates.y,
592                          rayOrigin,
593                          rayDirection,
594                          nearPlaneDistance);
595   }
596
597   return success;
598 }
599
600 const Matrix& CameraActor::GetViewMatrix() const
601 {
602   if(OnScene())
603   {
604     return mSceneObject->GetViewMatrix(GetEventThreadServices().GetEventBufferIndex());
605   }
606   else
607   {
608     return Matrix::IDENTITY;
609   }
610 }
611
612 const Matrix& CameraActor::GetProjectionMatrix() const
613 {
614   if(OnScene())
615   {
616     return mSceneObject->GetProjectionMatrix(GetEventThreadServices().GetEventBufferIndex());
617   }
618   else
619   {
620     return Matrix::IDENTITY;
621   }
622 }
623 const SceneGraph::Camera* CameraActor::GetCamera() const
624 {
625   return mSceneObject;
626 }
627
628 void CameraActor::RotateProjection(int rotationAngle)
629 {
630   // sceneObject is being used in a separate thread; queue a message to set
631   RotateProjectionMessage(GetEventThreadServices(), *mSceneObject, rotationAngle);
632 }
633
634 void CameraActor::SetDefaultProperty(Property::Index index, const Property::Value& propertyValue)
635 {
636   if(index < DEFAULT_ACTOR_PROPERTY_MAX_COUNT)
637   {
638     Actor::SetDefaultProperty(index, propertyValue);
639   }
640   else
641   {
642     switch(index)
643     {
644       case Dali::CameraActor::Property::TYPE:
645       {
646         Dali::Camera::Type cameraType = Dali::Camera::Type(propertyValue.Get<int>());
647         SetType(cameraType);
648         break;
649       }
650       case Dali::CameraActor::Property::PROJECTION_MODE:
651       {
652         Dali::Camera::ProjectionMode projectionMode = Dali::Camera::ProjectionMode(propertyValue.Get<int>());
653         SetProjectionMode(projectionMode);
654         break;
655       }
656       case Dali::CameraActor::Property::FIELD_OF_VIEW:
657       {
658         SetFieldOfView(propertyValue.Get<float>()); // set to 0 in case property is not float
659         break;
660       }
661       case Dali::CameraActor::Property::ASPECT_RATIO:
662       {
663         SetAspectRatio(propertyValue.Get<float>()); // set to 0 in case property is not float
664         break;
665       }
666       case Dali::CameraActor::Property::NEAR_PLANE_DISTANCE:
667       {
668         SetNearClippingPlane(propertyValue.Get<float>()); // set to 0 in case property is not float
669         break;
670       }
671       case Dali::CameraActor::Property::FAR_PLANE_DISTANCE:
672       {
673         SetFarClippingPlane(propertyValue.Get<float>()); // set to 0 in case property is not float
674         break;
675       }
676       case Dali::CameraActor::Property::LEFT_PLANE_DISTANCE:
677       {
678         SetLeftClippingPlane(propertyValue.Get<float>()); // set to 0 in case property is not float
679         break;
680       }
681       case Dali::CameraActor::Property::RIGHT_PLANE_DISTANCE:
682       {
683         SetRightClippingPlane(propertyValue.Get<float>()); // set to 0 in case property is not float
684         break;
685       }
686       case Dali::CameraActor::Property::TOP_PLANE_DISTANCE:
687       {
688         SetTopClippingPlane(propertyValue.Get<float>()); // set to 0 in case property is not float
689         break;
690       }
691       case Dali::CameraActor::Property::BOTTOM_PLANE_DISTANCE:
692       {
693         SetBottomClippingPlane(propertyValue.Get<float>()); // set to 0 in case property is not float
694         break;
695       }
696       case Dali::CameraActor::Property::TARGET_POSITION:
697       {
698         SetTarget(propertyValue.Get<Vector3>()); // set to 0 in case property is not Vector3
699         break;
700       }
701       case Dali::CameraActor::Property::PROJECTION_MATRIX:
702       {
703         DALI_LOG_WARNING("projection-matrix is read-only\n");
704         break;
705       }
706       case Dali::CameraActor::Property::VIEW_MATRIX:
707       {
708         DALI_LOG_WARNING("view-matrix is read-only\n");
709         break;
710       }
711       case Dali::CameraActor::Property::INVERT_Y_AXIS:
712       {
713         SetInvertYAxis(propertyValue.Get<bool>()); // set to false in case property is not bool
714         break;
715       }
716       case Dali::DevelCameraActor::Property::REFLECTION_PLANE:
717       {
718         SetReflectByPlane(propertyValue.Get<Vector4>());
719         break;
720       }
721       case Dali::DevelCameraActor::Property::PROJECTION_DIRECTION:
722       {
723         Dali::DevelCameraActor::ProjectionDirection projectionDirection = Dali::DevelCameraActor::ProjectionDirection(propertyValue.Get<int>());
724         SetProjectionDirection(projectionDirection);
725         break;
726       }
727
728       default:
729       {
730         DALI_LOG_WARNING("Unknown property (%d)\n", index);
731         break;
732       }
733     } // switch(index)
734
735   } // else
736 }
737
738 Property::Value CameraActor::GetDefaultProperty(Property::Index index) const
739 {
740   Property::Value ret;
741   if(index < DEFAULT_ACTOR_PROPERTY_MAX_COUNT)
742   {
743     ret = Actor::GetDefaultProperty(index);
744   }
745   else
746   {
747     switch(index)
748     {
749       case Dali::CameraActor::Property::TYPE:
750       {
751         ret = mType;
752         break;
753       }
754       case Dali::CameraActor::Property::PROJECTION_MODE:
755       {
756         ret = mProjectionMode;
757         break;
758       }
759       case Dali::CameraActor::Property::FIELD_OF_VIEW:
760       {
761         ret = mFieldOfView;
762         break;
763       }
764       case Dali::CameraActor::Property::ASPECT_RATIO:
765       {
766         ret = mAspectRatio;
767         break;
768       }
769       case Dali::CameraActor::Property::NEAR_PLANE_DISTANCE:
770       {
771         ret = mNearClippingPlane;
772         break;
773       }
774       case Dali::CameraActor::Property::FAR_PLANE_DISTANCE:
775       {
776         ret = mFarClippingPlane;
777         break;
778       }
779       case Dali::CameraActor::Property::LEFT_PLANE_DISTANCE:
780       {
781         ret = mLeftClippingPlane;
782         break;
783       }
784       case Dali::CameraActor::Property::RIGHT_PLANE_DISTANCE:
785       {
786         ret = mRightClippingPlane;
787         break;
788       }
789       case Dali::CameraActor::Property::TOP_PLANE_DISTANCE:
790       {
791         ret = mTopClippingPlane;
792         break;
793       }
794       case Dali::CameraActor::Property::BOTTOM_PLANE_DISTANCE:
795       {
796         ret = mBottomClippingPlane;
797         break;
798       }
799       case Dali::CameraActor::Property::TARGET_POSITION:
800       {
801         ret = mTarget;
802         break;
803       }
804       case Dali::CameraActor::Property::PROJECTION_MATRIX:
805       {
806         ret = GetProjectionMatrix(); // Only on scene-graph
807         break;
808       }
809       case Dali::CameraActor::Property::VIEW_MATRIX:
810       {
811         ret = GetViewMatrix(); // Only on scene-graph
812         break;
813       }
814       case Dali::CameraActor::Property::INVERT_Y_AXIS:
815       {
816         ret = mInvertYAxis;
817         break;
818       }
819       case Dali::DevelCameraActor::Property::PROJECTION_DIRECTION:
820       {
821         ret = mProjectionDirection;
822         break;
823       }
824     } // switch(index)
825   }
826
827   return ret;
828 }
829
830 Property::Value CameraActor::GetDefaultPropertyCurrentValue(Property::Index index) const
831 {
832   Property::Value ret;
833   if(index < DEFAULT_ACTOR_PROPERTY_MAX_COUNT)
834   {
835     ret = Actor::GetDefaultPropertyCurrentValue(index);
836   }
837   else
838   {
839     ret = GetDefaultProperty(index); // Most are event-side properties, the scene-graph properties are only on the scene-graph
840   }
841
842   return ret;
843 }
844
845 const PropertyInputImpl* CameraActor::GetSceneObjectInputProperty(Property::Index index) const
846 {
847   const PropertyInputImpl* property(nullptr);
848
849   switch(index)
850   {
851     case Dali::CameraActor::Property::PROJECTION_MATRIX:
852     {
853       property = mSceneObject->GetProjectionMatrix();
854       break;
855     }
856     case Dali::CameraActor::Property::VIEW_MATRIX:
857     {
858       property = mSceneObject->GetViewMatrix();
859       break;
860     }
861       // no default on purpose as we chain method up to actor
862   }
863   if(!property)
864   {
865     property = Actor::GetSceneObjectInputProperty(index);
866   }
867
868   return property;
869 }
870
871 void CameraActor::OnPropertySet(Property::Index index, const Property::Value& propertyValue)
872 {
873   // If Position or Orientation are explicitly set, make mPropertyChanged flag true.
874   if(index == Dali::Actor::Property::POSITION ||
875      index == Dali::Actor::Property::POSITION_X ||
876      index == Dali::Actor::Property::POSITION_Y ||
877      index == Dali::Actor::Property::POSITION_Z ||
878      index == Dali::Actor::Property::ORIENTATION)
879   {
880     mPropertyChanged = true;
881   }
882 }
883
884 } // namespace Internal
885
886 } // namespace Dali