Dali 3D User Interface Engine
camera-actor-impl.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2014 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
20 
21 // EXTERNAL INCLUDES
22 #include <cmath>
23 #include <cstring> // for strcmp
24 
25 // INTERNAL INCLUDES
35 
36 namespace Dali
37 {
38 
39 namespace Internal
40 {
41 
42 namespace
43 {
44 
45 // Properties
46 
53 DALI_PROPERTY( "type", STRING, true, false, true, Dali::CameraActor::Property::TYPE )
54 DALI_PROPERTY( "projectionMode", STRING, true, false, true, Dali::CameraActor::Property::PROJECTION_MODE )
55 DALI_PROPERTY( "fieldOfView", FLOAT, true, false, true, Dali::CameraActor::Property::FIELD_OF_VIEW )
56 DALI_PROPERTY( "aspectRatio", FLOAT, true, false, true, Dali::CameraActor::Property::ASPECT_RATIO )
57 DALI_PROPERTY( "nearPlaneDistance", FLOAT, true, false, true, Dali::CameraActor::Property::NEAR_PLANE_DISTANCE )
58 DALI_PROPERTY( "farPlaneDistance", FLOAT, true, false, true, Dali::CameraActor::Property::FAR_PLANE_DISTANCE )
59 DALI_PROPERTY( "leftPlaneDistance", FLOAT, true, false, true, Dali::CameraActor::Property::LEFT_PLANE_DISTANCE )
60 DALI_PROPERTY( "rightPlaneDistance", FLOAT, true, false, true, Dali::CameraActor::Property::RIGHT_PLANE_DISTANCE )
61 DALI_PROPERTY( "topPlaneDistance", FLOAT, true, false, true, Dali::CameraActor::Property::TOP_PLANE_DISTANCE )
62 DALI_PROPERTY( "bottomPlaneDistance", FLOAT, true, false, true, Dali::CameraActor::Property::BOTTOM_PLANE_DISTANCE )
63 DALI_PROPERTY( "targetPosition", VECTOR3, true, false, true, Dali::CameraActor::Property::TARGET_POSITION )
64 DALI_PROPERTY( "projectionMatrix", MATRIX, false, false, true, Dali::CameraActor::Property::PROJECTION_MATRIX )
65 DALI_PROPERTY( "viewMatrix", MATRIX, false, false, true, Dali::CameraActor::Property::VIEW_MATRIX )
66 DALI_PROPERTY( "invertYAxis", BOOLEAN, true, false, true, Dali::CameraActor::Property::INVERT_Y_AXIS )
68 
69 // calculate the far plane distance for a 16bit depth buffer with 4 bits per unit precision
70 void CalculateClippingAndZ( float width, float height, float& nearClippingPlane, float& farClippingPlane, float& cameraZ )
71 {
72  nearClippingPlane = std::max( width, height );
73  farClippingPlane = nearClippingPlane + static_cast<float>( 0xFFFF >> 4 );
74  cameraZ = 2.0f * nearClippingPlane;
75 }
76 
78 {
79  return Dali::CameraActor::New();
80 }
81 
83 
90 void BuildOrthoPickingRay( const Matrix& viewMatrix,
91  const Matrix& projectionMatrix,
92  const Viewport& viewport,
93  float screenX,
94  float screenY,
95  Vector4& rayOrigin,
96  Vector4& rayDir,
97  float nearPlaneDistance )
98 {
99  // inv( modelMatrix ) inv( viewMatrix ) inv( projectionMatrix ) normalize
100  // <----------------- <----------------- <-------------- <-------------
101  // Local World Camera Normalized Screen
102  // reference reference reference clip coordinates
103  // system system system coordinates
104  // -----------------> -----------------> --------------> ------------->
105  // modelMatrix viewMatrix projectionMatrix viewport
106 
107  // Transforms the touch point from the screen reference system to the world reference system.
108  Matrix invViewProjection( false ); // Don't initialize.
109  Matrix::Multiply( invViewProjection, viewMatrix, projectionMatrix );
110  if( !invViewProjection.Invert() )
111  {
112  DALI_ASSERT_DEBUG( false );
113  }
114 
115  Vector4 near( screenX - viewport.x, viewport.height - (screenY - viewport.y), 0.f, 1.f );
116  if( !Unproject( near, invViewProjection, viewport.width, 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 } // namespace
138 
140 {
141  CameraActorPtr actor(new CameraActor());
142 
143  // Second-phase construction
144 
145  actor->Initialize();
146 
147  actor->SetName("DefaultCamera");
148 
149  // Create the attachment
150  actor->mCameraAttachment = CameraAttachment::New( actor->GetEventThreadServices(), *actor->mNode );
151 
152  actor->Attach(*actor->mCameraAttachment);
153 
154  actor->SetPerspectiveProjection( size );
155 
156  // By default Actors face in the positive Z direction in world space
157  // CameraActors should face in the negative Z direction, towards the other actors
159 
160  return actor;
161 }
162 
164 {
165 }
166 
168 : Actor( Actor::BASIC )
169 {
170 }
171 
173 {
174 }
175 
177 {
178  mCameraAttachment->SetType(type);
179 }
180 
182 {
183  return mCameraAttachment->GetType();
184 }
185 
187 {
188  mCameraAttachment->SetProjectionMode(mode);
189 }
190 
192 {
193  return mCameraAttachment->GetProjectionMode();
194 }
195 
196 void CameraActor::SetFieldOfView( float fieldOfView )
197 {
198  mCameraAttachment->SetFieldOfView(fieldOfView);
199 }
200 
202 {
203  return mCameraAttachment->GetFieldOfView();
204 }
205 
206 void CameraActor::SetAspectRatio( float aspectRatio )
207 {
208  mCameraAttachment->SetAspectRatio(aspectRatio);
209 }
210 
212 {
213  return mCameraAttachment->GetAspectRatio();
214 }
215 
216 void CameraActor::SetNearClippingPlane( float nearClippingPlane )
217 {
218  mCameraAttachment->SetNearClippingPlane(nearClippingPlane);
219 }
220 
222 {
223  return mCameraAttachment->GetNearClippingPlane();
224 }
225 
226 void CameraActor::SetFarClippingPlane( float farClippingPlane )
227 {
228  mCameraAttachment->SetFarClippingPlane(farClippingPlane);
229 }
230 
232 {
233  return mCameraAttachment->GetFarClippingPlane();
234 }
235 
237 {
238  mCameraAttachment->SetTargetPosition(target);
239 }
240 
242 {
243  return mCameraAttachment->GetTargetPosition();
244 }
245 
246 void CameraActor::SetInvertYAxis(bool invertYAxis)
247 {
248  mCameraAttachment->SetInvertYAxis(invertYAxis);
249 }
250 
252 {
253  return mCameraAttachment->GetInvertYAxis();
254 }
255 
256 void CameraActor::SetPerspectiveProjection( const Size& size, const Vector2& stereoBias /* = Vector2::ZERO */ )
257 {
258  float width = size.width;
259  float height = size.height;
260 
261  if( Size::ZERO == size )
262  {
263  StagePtr stage = Stage::GetCurrent();
264  if( stage )
265  {
266  const Size& stageSize = stage->GetSize();
267 
268  width = stageSize.width;
269  height = stageSize.height;
270  }
271  }
272 
273  if( ( width < Math::MACHINE_EPSILON_1000 ) || ( height < Math::MACHINE_EPSILON_1000 ) )
274  {
275  // On the stage initialization this method is called but the size has not been set.
276  // There is no point to set any value if width or height is zero.
277  return;
278  }
279 
280  float nearClippingPlane;
281  float farClippingPlane;
282  float cameraZ;
283  CalculateClippingAndZ( width, height, nearClippingPlane, farClippingPlane, cameraZ );
284 
285  // calculate the position of the camera to have the desired aspect ratio
286  const float fieldOfView = 2.0f * std::atan( height * 0.5f / cameraZ );
287 
288  // unless it is too small, we want at least as much space to the back as we have torwards the front
289  const float minClippingFarPlane = 2.f * nearClippingPlane;
290  if ( farClippingPlane < minClippingFarPlane )
291  {
292  farClippingPlane = minClippingFarPlane;
293  }
294 
295  const float aspectRatio = width / height;
296 
298  SetFieldOfView( fieldOfView );
299  SetNearClippingPlane( nearClippingPlane );
300  SetFarClippingPlane( farClippingPlane );
301  SetAspectRatio( aspectRatio );
302  mCameraAttachment->SetStereoBias( stereoBias );
303  SetZ( cameraZ );
304 }
305 
306 
308 {
309  // Choose near, far and Z parameters to match the SetPerspectiveProjection above.
310  float nearClippingPlane;
311  float farClippingPlane;
312  float cameraZ;
313  CalculateClippingAndZ( size.width, size.height, nearClippingPlane, farClippingPlane, cameraZ );
314  SetOrthographicProjection( -size.x*0.5f, size.x*0.5f, size.y*0.5f, -size.y*0.5f,
315  nearClippingPlane, farClippingPlane );
316  SetZ( cameraZ );
317 }
318 
319 void CameraActor::SetOrthographicProjection( float left, float right, float top, float bottom, float near, float far )
320 {
321  mCameraAttachment->SetLeftClippingPlane(left);
322  mCameraAttachment->SetRightClippingPlane(right);
323  mCameraAttachment->SetTopClippingPlane(top);
324  mCameraAttachment->SetBottomClippingPlane(bottom);
325  SetNearClippingPlane( near );
326  SetFarClippingPlane( far );
328 }
329 
330 bool CameraActor::BuildPickingRay( const Vector2& screenCoordinates,
331  const Viewport& viewport,
332  Vector4& rayOrigin,
333  Vector4& rayDirection )
334 {
335  bool success = true;
337  {
338  // Build a picking ray in the world reference system.
339  // ray starts from the camera world position
340  rayOrigin = mNode->GetWorldPosition( GetEventThreadServices().GetEventBufferIndex() );
341  rayOrigin.w = 1.0f;
342 
343  // Transform the touch point from the screen coordinate system to the world coordinates system.
344  Vector4 near( screenCoordinates.x - viewport.x, viewport.height - (screenCoordinates.y - viewport.y), 0.f, 1.f );
345  if( !Unproject( near, mCameraAttachment->GetInverseViewProjectionMatrix(), viewport.width, viewport.height, near ) )
346  {
347  // unproject failed so no picking ray possible
348  success = false;
349  }
350 
351  // Compute the ray's director vector.
352  rayDirection.x = near.x - rayOrigin.x;
353  rayDirection.y = near.y - rayOrigin.y;
354  rayDirection.z = near.z - rayOrigin.z;
355  rayDirection.Normalize();
356  rayDirection.w = 1.f;
357  }
358  else
359  {
360  float nearPlaneDistance = GetNearClippingPlane();
363  viewport, screenCoordinates.x,
364  screenCoordinates.y,
365  rayOrigin,
366  rayDirection,
367  nearPlaneDistance );
368  }
369 
370  return success;
371 }
372 
374 {
375  if ( OnStage() )
376  {
377  return mCameraAttachment->GetViewMatrix();
378  }
379  else
380  {
381  return Matrix::IDENTITY;
382  }
383 }
384 
386 {
387  if ( OnStage() )
388  {
389  return mCameraAttachment->GetProjectionMatrix();
390  }
391  else
392  {
393  return Matrix::IDENTITY;
394  }
395 }
396 
398 {
399  return Actor::GetDefaultPropertyCount() + DEFAULT_PROPERTY_COUNT;
400 }
401 
403 {
404  Actor::GetDefaultPropertyIndices( indices ); // Actor class properties
405 
406  indices.Reserve( indices.Size() + DEFAULT_PROPERTY_COUNT );
407 
409  for ( int i = 0; i < DEFAULT_PROPERTY_COUNT; ++i, ++index )
410  {
411  indices.PushBack( index );
412  }
413 }
414 
416 {
418  {
419  return Actor::IsDefaultPropertyWritable( index );
420  }
421 
422  return DEFAULT_PROPERTY_DETAILS[index - DEFAULT_DERIVED_ACTOR_PROPERTY_START_INDEX].writable;
423 }
424 
426 {
428  {
429  return Actor::IsDefaultPropertyAnimatable( index );
430  }
431 
432  return DEFAULT_PROPERTY_DETAILS[index - DEFAULT_DERIVED_ACTOR_PROPERTY_START_INDEX].animatable;
433 }
434 
436 {
438  {
440  }
441 
442  return DEFAULT_PROPERTY_DETAILS[index - DEFAULT_DERIVED_ACTOR_PROPERTY_START_INDEX].constraintInput;
443 }
444 
446 {
448  {
449  return Actor::GetDefaultPropertyType( index );
450  }
451  else
452  {
454 
455  if ( ( index >= 0 ) && ( index < DEFAULT_PROPERTY_COUNT ) )
456  {
457  return DEFAULT_PROPERTY_DETAILS[index].type;
458  }
459  else
460  {
461  // index out-of-bounds
462  return Property::NONE;
463  }
464  }
465 }
466 
468 {
470  {
471  return Actor::GetDefaultPropertyName(index);
472  }
473  else
474  {
476 
477  if ( ( index >= 0 ) && ( index < DEFAULT_PROPERTY_COUNT ) )
478  {
479  return DEFAULT_PROPERTY_DETAILS[index].name;
480  }
481  return NULL;
482  }
483 }
484 
486 {
488 
489  // Look for name in current class' default properties
490  for( int i = 0; i < DEFAULT_PROPERTY_COUNT; ++i )
491  {
492  if( 0 == strcmp( name.c_str(), DEFAULT_PROPERTY_DETAILS[i].name ) ) // dont want to convert rhs to string
493  {
495  break;
496  }
497  }
498 
499  // If not found, check in base class
500  if( Property::INVALID_INDEX == index )
501  {
502  index = Actor::GetDefaultPropertyIndex( name );
503  }
504 
505  return index;
506 }
507 
509 {
511  {
512  Actor::SetDefaultProperty(index, propertyValue);
513  }
514  else
515  {
516  DALI_ASSERT_DEBUG(mCameraAttachment && "where is the camera?");
517  switch(index)
518  {
520  {
521  std::string s( propertyValue.Get<std::string>() );
522  if(s == "LOOK_AT_TARGET")
523  {
525  }
526  else if(s == "FREE_LOOK")
527  {
529  }
530  else
531  {
532  DALI_LOG_WARNING("Unknown camera type\n");
533  }
534  break;
535  }
537  {
538  std::string s(propertyValue.Get<std::string>());
539  if(s == "PERSPECTIVE_PROJECTION")
540  {
542  }
543  else if(s == "ORTHOGRAPHIC_PROJECTION")
544  {
546  }
547  else
548  {
549  DALI_LOG_WARNING("Unknown projection mode\n");
550  }
551  break;
552  }
554  {
555  mCameraAttachment->SetFieldOfView(propertyValue.Get<float>());
556  break;
557  }
559  {
560  mCameraAttachment->SetAspectRatio(propertyValue.Get<float>());
561  break;
562  }
564  {
565  mCameraAttachment->SetLeftClippingPlane(propertyValue.Get<float>());
566  break;
567  }
569  {
570  mCameraAttachment->SetRightClippingPlane(propertyValue.Get<float>());
571  break;
572  }
574  {
575  mCameraAttachment->SetTopClippingPlane(propertyValue.Get<float>());
576  break;
577  }
579  {
580  mCameraAttachment->SetBottomClippingPlane(propertyValue.Get<float>());
581  break;
582  }
584  {
585  mCameraAttachment->SetNearClippingPlane(propertyValue.Get<float>());
586  break;
587  }
589  {
590  mCameraAttachment->SetFarClippingPlane(propertyValue.Get<float>());
591  break;
592  }
594  {
595  mCameraAttachment->SetTargetPosition(propertyValue.Get<Vector3>());
596  break;
597  }
599  {
600  DALI_LOG_WARNING("projection-matrix property is not animatable \n");
601  break;
602  }
604  {
605  DALI_LOG_WARNING("view-matrix property is not animatable \n");
606  break;
607  }
609  {
610  mCameraAttachment->SetInvertYAxis(propertyValue.Get<bool>());
611  break;
612  }
613  default:
614  {
615  DALI_LOG_WARNING("Unknown property (%d)\n", index);
616  break;
617  }
618  } // switch(index)
619 
620  } // else
621 }
622 
624 {
625  Property::Value ret;
627  {
628  ret = Actor::GetDefaultProperty(index);
629  }
630  else
631  {
632  DALI_ASSERT_DEBUG(mCameraAttachment && "where is the camera?");
633  switch(index)
634  {
636  {
638  {
639  ret = "LOOK_AT_TARGET";
640  }
641  else if(mCameraAttachment->GetType() == Dali::Camera::FREE_LOOK)
642  {
643  ret = "FREE_LOOK";
644  }
645  else
646  {
647  ret = "";
648  DALI_ASSERT_DEBUG("Unknown camera type\n");
649  }
650  break;
651  }
653  {
654  if(mCameraAttachment->GetProjectionMode() == Dali::Camera::PERSPECTIVE_PROJECTION)
655  {
656  ret = "PERSPECTIVE_PROJECTION";
657  }
658  else if(mCameraAttachment->GetProjectionMode() == Dali::Camera::ORTHOGRAPHIC_PROJECTION)
659  {
660  ret = "ORTHOGRAPHIC_PROJECTION";
661  }
662  else
663  {
664  ret = "";
665  DALI_ASSERT_DEBUG("Unknown projection mode\n");
666  }
667  break;
668  }
670  {
671  ret = mCameraAttachment->GetFieldOfView();
672  break;
673  }
675  {
676  ret = mCameraAttachment->GetAspectRatio();
677  break;
678  }
680  {
681  ret = mCameraAttachment->GetLeftClippingPlane();
682  break;
683  }
685  {
686  ret = mCameraAttachment->GetRightClippingPlane();
687  break;
688  }
690  {
691  ret = mCameraAttachment->GetTopClippingPlane();
692  break;
693  }
695  {
696  ret = mCameraAttachment->GetBottomClippingPlane();
697  break;
698  }
700  {
701  ret = mCameraAttachment->GetNearClippingPlane();
702  break;
703  }
705  {
706  ret = mCameraAttachment->GetFarClippingPlane();
707  break;
708  }
710  {
711  ret = mCameraAttachment->GetTargetPosition();
712  break;
713  }
715  {
716  ret = mCameraAttachment->GetProjectionMatrix();
717  break;
718  }
720  {
721  ret = mCameraAttachment->GetViewMatrix();
722  break;
723  }
725  {
726  ret = mCameraAttachment->GetInvertYAxis();
727  break;
728  }
729  default:
730  {
731  DALI_LOG_WARNING("Unknown property (%d)\n", index);
732  break;
733  }
734  } // switch(index)
735  }
736 
737  return ret;
738 }
739 
741 {
742  DALI_ASSERT_ALWAYS( IsPropertyAnimatable(index) && "Property is not animatable" );
743 
744  const SceneGraph::PropertyBase* property( NULL );
745 
746  // This method should only return a property of an object connected to the scene-graph
747  if ( !OnStage() )
748  {
749  return property;
750  }
751 
752  // let actor handle animatable properties, we have no animatable properties
754  {
755  property = Actor::GetSceneObjectAnimatableProperty(index);
756  }
757 
758  return property;
759 }
760 
762 {
763  const PropertyInputImpl* property( NULL );
764 
765  // This method should only return a property of an object connected to the scene-graph
766  if ( !OnStage() )
767  {
768  return property;
769  }
770 
771  // if its an actor default property or a custom property (actor already handles custom properties)
772  if( ( index < DEFAULT_ACTOR_PROPERTY_MAX_COUNT ) || ( index >= DEFAULT_PROPERTY_MAX_COUNT ) )
773  {
774  property = Actor::GetSceneObjectInputProperty(index);
775  }
776  else
777  {
778  switch( index )
779  {
781  {
782  property = mCameraAttachment->GetProjectionMatrixProperty();
783  break;
784  }
786  {
787  property = mCameraAttachment->GetViewMatrixProperty();
788  break;
789  }
790  default:
791  DALI_LOG_WARNING("Not an input property (%d)\n", index);
792  break;
793  }
794  }
795 
796  return property;
797 }
798 
799 
800 } // namespace Internal
801 
802 } // namespace Dali
Dali Docs Home
Read more about Dali