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