Dali 3D User Interface Engine
stage-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 <algorithm>
23 #include <cmath>
24 #include <cstring> // for strcmp
25 
26 // INTERNAL INCLUDES
42 
44 
45 namespace Dali
46 {
47 
48 namespace Internal
49 {
50 
51 namespace
52 {
53 
54 const float DEFAULT_STEREO_BASE( 65.0f );
55 
56 // Signals
57 
58 const char* const SIGNAL_KEY_EVENT = "keyEvent";
59 const char* const SIGNAL_EVENT_PROCESSING_FINISHED = "eventProcessingFinished";
60 const char* const SIGNAL_TOUCHED = "touched";
61 const char* const SIGNAL_WHEEL_EVENT = "wheelEvent";
62 const char* const SIGNAL_CONTEXT_LOST = "contextLost";
63 const char* const SIGNAL_CONTEXT_REGAINED = "contextRegained";
64 const char* const SIGNAL_SCENE_CREATED = "sceneCreated";
65 
66 TypeRegistration mType( typeid(Dali::Stage), typeid(Dali::BaseHandle), NULL );
67 
69 SignalConnectorType signalConnector2( mType, SIGNAL_EVENT_PROCESSING_FINISHED, &Stage::DoConnectSignal );
75 
76 } // unnamed namespace
77 
79  PropertyNotificationManager& propertyNotificationManager,
80  SceneGraph::UpdateManager& updateManager,
81  NotificationManager& notificationManager )
82 {
83  return StagePtr( new Stage( playlist, propertyNotificationManager, updateManager, notificationManager ) );
84 }
85 
87 {
89 
90  // Create the ordered list of layers
91  mLayerList = LayerList::New( mUpdateManager, false/*not system-level*/ );
92 
93  // The stage owns the default layer
94  mRootLayer = Layer::NewRoot( *mLayerList, mUpdateManager, false/*not system-level*/ );
95  mRootLayer->SetName("RootLayer");
96  // The root layer needs to have a fixed resize policy (as opposed to the default USE_NATURAL_SIZE).
97  // This stops actors parented to the stage having their relayout requests propagating
98  // up to the root layer, and down through other children unnecessarily.
100 
101  // Create the default camera actor first; this is needed by the RenderTaskList
103 
104  // Create the list of render-tasks
105  mRenderTaskList = RenderTaskList::New( *this, *this, false/*not system-level*/ );
106 
107  // Create the default render-task
108  Dali::RenderTask defaultRenderTask = mRenderTaskList->CreateTask();
109 }
110 
112 {
113  // Remove actors added to SystemOverlay
114  delete mSystemOverlay;
115  mSystemOverlay = NULL;
116 
117  if( mDefaultCamera )
118  {
119  // its enough to release the handle so the object is released
120  // don't need to remove it from root actor as root actor will delete the object
122  }
123 
124  if( mRootLayer )
125  {
126  // we are closing down so just delete the root, no point emit disconnect
127  // signals or send messages to update
128  mRootLayer.Reset();
129  }
130 }
131 
133 {
134  StagePtr stage( NULL );
135  // no checking in this version
137  if( tls )
138  {
139  stage = tls->GetCurrentStage();
140  }
141  return stage;
142 }
143 
145 {
147 }
148 
150 {
151  return *mObjectRegistry;
152 }
153 
155 {
156  mObjectRegistry->RegisterObject( object );
157 }
158 
160 {
161  mObjectRegistry->UnregisterObject( object );
162 }
163 
165 {
166  return *mRootLayer;
167 }
168 
170 {
171  return mAnimationPlaylist;
172 }
173 
175 {
177 }
178 
179 void Stage::Add( Actor& actor )
180 {
181  mRootLayer->Add( actor );
182 }
183 
184 void Stage::Remove( Actor& actor )
185 {
186  mRootLayer->Remove( actor );
187 }
188 
189 void Stage::SetSize(float width, float height)
190 {
191  // Internally we want to report the actual size of the stage.
192  mSize.width = width;
193  mSize.height = height;
194 
195  // Calculates the aspect ratio, near and far clipping planes, field of view and camera Z position.
197 
198  // The depth of the stage gets set to the maximun of these values
200 
201  // Repeat for SystemOverlay actors
202  if( mSystemOverlay )
203  {
204  mSystemOverlay->GetImpl()->SetSize( mSize.width, mSize.height );
205  }
206 
207  SetDefaultSurfaceRectMessage( mUpdateManager, Rect<int>( 0, 0, width, height ) );
208 
209  // if single render task to screen then set its viewport parameters
210  if( 1 == mRenderTaskList->GetTaskCount() )
211  {
212  Dali::RenderTask mDefaultRenderTask = mRenderTaskList->GetTask(0);
213 
214  if(!mDefaultRenderTask.GetTargetFrameBuffer())
215  {
216  mDefaultRenderTask.SetViewport( Viewport(0, 0, width, height) );
217  }
218  }
219 
220 }
221 
223 {
224  return mSize;
225 }
226 
228 {
229  return *mRenderTaskList;
230 }
231 
233 {
234  // The default camera attributes and position is such that
235  // children of the default layer, can be positioned at (0,0) and
236  // be at the top-left of the viewport.
239  Add(*(mDefaultCamera.Get()));
240 }
241 
243 {
244  return *mRootLayer;
245 }
246 
248 {
249  return *mDefaultCamera;
250 }
251 
252 unsigned int Stage::GetLayerCount() const
253 {
254  return mLayerList->GetLayerCount();
255 }
256 
257 Dali::Layer Stage::GetLayer( unsigned int depth ) const
258 {
259  return Dali::Layer(mLayerList->GetLayer( depth ));
260 }
261 
263 {
264  return Dali::Layer( mRootLayer.Get() );
265 }
266 
268 {
269  return *mLayerList;
270 }
271 
273 {
274  // Lazily create system-level if requested
275  if( !mSystemOverlay )
276  {
278  DALI_ASSERT_ALWAYS( NULL != mSystemOverlay && "Failed to create system overlay" );
279 
280  mSystemOverlay->GetImpl()->SetSize( mSize.width, mSize.height );
281  }
282 
283  return *mSystemOverlay;
284 }
285 
287 {
288  SystemOverlay* overlay( NULL );
289 
290  if( mSystemOverlay )
291  {
292  overlay = mSystemOverlay->GetImpl();
293  }
294 
295  return overlay;
296 }
297 
298 void Stage::SetViewMode( ViewMode viewMode )
299 {
300  if( mViewMode != viewMode )
301  {
302  DALI_LOG_INFO( Debug::Filter::gActor, Debug::Concise, "View mode changed from %d to %d\n", mViewMode, viewMode);
303 
304  if( mViewMode == MONO )
305  {
307  mRenderTaskList->GetTask(0).SetSourceActor( Dali::Actor() );
308 
309  //Create camera and RenderTask for left eye
313  mLeftRenderTask = mRenderTaskList->CreateTask();
316 
317  //Create camera and RenderTask for right eye
321  mRightRenderTask = mRenderTaskList->CreateTask();
322  mRightRenderTask.SetClearColor( Vector4( 1.0f,0.0f,0.0f,1.0f));
323 
326  }
327 
328  // save new mode
329  mViewMode = viewMode;
330 
331  switch( viewMode )
332  {
333  case MONO:
334  {
335  // delete extra stereoscopic render tasks and cameras
336  mRenderTaskList->RemoveTask( mLeftRenderTask );
339  mLeftCamera.Reset();
340  mRenderTaskList->RemoveTask( mRightRenderTask );
346  mRenderTaskList->GetTask(0).SetSourceActor( Dali::Layer(mRootLayer.Get()) );
347 
348  break;
349  }
350  case STEREO_HORIZONTAL:
351  {
352  //Stereo mode with horizontal split is for landscape mode. That's the reason for the cameras being rotated
353  //Top camera renders the scene as seen from the right eye and bottom camera as seen from left.
354 
355  //Calculate separation in pixels along vertical axis ( mStereoBase is defined in millimetres )
356  const float stereoBase( ( (mStereoBase / 25.4f) * GetDpi().y ) * 0.5f );
357 
358  //Calculate aspect ratio
359  float aspect = mSize.width / (mSize.height * 0.5f);
360 
361  mLeftCamera->SetPerspectiveProjection( mSize, Vector2( 0.0f,stereoBase) );
362  mLeftCamera->SetAspectRatio( aspect );
363 
365  mLeftCamera->SetPosition( Vector3( stereoBase, 0.0f, 0.0f ) );
367 
368  mRightCamera->SetPerspectiveProjection( mSize, Vector2( 0.0, -stereoBase) );
369  mRightCamera->SetAspectRatio( aspect );
371  mRightCamera->SetPosition( Vector3(-stereoBase, 0.0f, 0.0f ) );
373 
374  break;
375  }
376  case STEREO_VERTICAL:
377  {
378  //Calculate separation in pixels along horizontal axis
379  const float stereoBase( ( (mStereoBase / 25.4f) * GetDpi().x ) * 0.5f );
380 
381  //Recalculate fov based on viewport size
382  const float fov = 2.0f * std::atan( mSize.y / (2.0f * std::max( mSize.x*0.5f, mSize.y )) );
383 
384  mLeftCamera->SetPerspectiveProjection( Size( mSize.x * 0.5f, mSize.y ), Vector2(stereoBase,0.0f) );
385  mLeftCamera->SetFieldOfView( fov );
387  mLeftCamera->SetPosition( Vector3( stereoBase, 0.0f, 0.0f ) );
389 
390  mRightCamera->SetPerspectiveProjection( Size( mSize.x * 0.5f, mSize.y ), Vector2(-stereoBase,0.0f) );
393  mRightCamera->SetPosition( Vector3( -stereoBase, 0.0f, 0.0f ) );
395 
396  break;
397  }
398  case STEREO_INTERLACED:
399  {
400  break;
401  }
402  }
403  }
404 }
405 
407 {
408  return mViewMode;
409 }
410 
411 void Stage::SetStereoBase( float stereoBase )
412 {
413  if( ! Equals( mStereoBase, stereoBase ) )
414  {
415  DALI_LOG_INFO( Debug::Filter::gActor, Debug::Concise, "old( %.2f) new(%.2f)", mStereoBase, stereoBase );
416  mStereoBase = stereoBase;
417 
418  switch( mViewMode )
419  {
420  case STEREO_HORIZONTAL:
421  {
422  stereoBase = mStereoBase / 25.4f * GetDpi().y * 0.5f;
423  float aspect = mSize.width / (mSize.height * 0.5f);
424 
425  mLeftCamera->SetPerspectiveProjection( mSize, Vector2( 0.0, stereoBase) );
426  mLeftCamera->SetAspectRatio( aspect );
427  mLeftCamera->SetPosition( Vector3( stereoBase, 0.0f, 0.0f ) );
428 
429  mRightCamera->SetPerspectiveProjection( mSize, Vector2( 0.0, -stereoBase) );
430  mRightCamera->SetAspectRatio( aspect );
431  mRightCamera->SetPosition( Vector3(-stereoBase, 0.0f, 0.0f ) );
432 
433  break;
434  }
435  case STEREO_VERTICAL:
436  {
437  stereoBase = mStereoBase / 25.4f * GetDpi().x * 0.5f;
438  const float fov = 2.0f * std::atan( mSize.y / (2.0f * std::max( mSize.x*0.5f, mSize.y )) );
439 
440  mLeftCamera->SetPerspectiveProjection( Size( mSize.x * 0.5f, mSize.y ), Vector2(stereoBase,0.0f) );
441  mLeftCamera->SetFieldOfView( fov );
442  mLeftCamera->SetPosition( Vector3( stereoBase, 0.0f, 0.0f ) );
443 
444  mRightCamera->SetPerspectiveProjection( Size( mSize.x * 0.5f, mSize.y ), Vector2(-stereoBase,0.0f) );
446  mRightCamera->SetPosition( Vector3(-stereoBase, 0.0f, 0.0f ) );
447 
448  break;
449  }
450  default:
451  break;
452  }
453  }
454 }
455 
456 float Stage::GetStereoBase() const
457 {
458  return mStereoBase;
459 }
460 
462 {
463  // Cache for public GetBackgroundColor()
464  mBackgroundColor = color;
465 
466  // Send message to change color in next frame
468 }
469 
471 {
472  return mBackgroundColor;
473 }
474 
476 {
477  return mDpi;
478 }
479 
481 {
482  mDpi = dpi;
483 }
484 
485 void Stage::KeepRendering( float durationSeconds )
486 {
487  // Send message to keep rendering
488  KeepRenderingMessage( mUpdateManager, durationSeconds );
489 }
490 
491 bool Stage::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor )
492 {
493  bool connected( true );
494  Stage* stage = dynamic_cast<Stage*>(object);
495 
496  if( 0 == strcmp( signalName.c_str(), SIGNAL_KEY_EVENT ) )
497  {
498  stage->KeyEventSignal().Connect( tracker, functor );
499  }
500  else if( 0 == strcmp( signalName.c_str(), SIGNAL_EVENT_PROCESSING_FINISHED ) )
501  {
502  stage->EventProcessingFinishedSignal().Connect( tracker, functor );
503  }
504  else if( 0 == strcmp( signalName.c_str(), SIGNAL_TOUCHED ) )
505  {
506  stage->TouchedSignal().Connect( tracker, functor );
507  }
508  else if( 0 == strcmp( signalName.c_str(), SIGNAL_WHEEL_EVENT ) )
509  {
510  stage->WheelEventSignal().Connect( tracker, functor );
511  }
512  else if( 0 == strcmp( signalName.c_str(), SIGNAL_CONTEXT_LOST ) )
513  {
514  stage->ContextLostSignal().Connect( tracker, functor );
515  }
516  else if( 0 == strcmp( signalName.c_str(), SIGNAL_CONTEXT_REGAINED ) )
517  {
518  stage->ContextRegainedSignal().Connect( tracker, functor );
519  }
520  else if( 0 == strcmp( signalName.c_str(), SIGNAL_SCENE_CREATED ) )
521  {
522  stage->SceneCreatedSignal().Connect( tracker, functor );
523  }
524  else
525  {
526  // signalName does not match any signal
527  connected = false;
528  }
529 
530  return connected;
531 }
532 
534 {
535  // Emit the key event signal when no actor in the stage has gained the key input focus
536 
537  mKeyEventSignal.Emit( event );
538 }
539 
541 {
543 }
544 
546 {
547  mTouchedSignal.Emit( touch );
548 }
549 
551 {
552  // Emit the wheel event signal when no actor in the stage has gained the wheel input focus
553 
554  mWheelEventSignal.Emit( event );
555 }
556 
558 {
560 }
561 
563 {
564  return mKeyEventSignal;
565 }
566 
568 {
570 }
571 
573 {
574  return mTouchedSignal;
575 }
576 
578 {
579  return mWheelEventSignal;
580 }
581 
583 {
584  return mContextLostSignal;
585 }
586 
588 {
589  return mContextRegainedSignal;
590 }
591 
593 {
594  return mSceneCreatedSignal;
595 }
596 
598 {
600 }
601 
603 {
605 }
606 
608  PropertyNotificationManager& propertyNotificationManager,
609  SceneGraph::UpdateManager& updateManager,
610  NotificationManager& notificationManager )
611 : mAnimationPlaylist( playlist ),
612  mPropertyNotificationManager(propertyNotificationManager),
613  mUpdateManager(updateManager),
614  mNotificationManager(notificationManager),
615  mSize(Vector2::ZERO),
616  mBackgroundColor(Dali::Stage::DEFAULT_BACKGROUND_COLOR),
617  mViewMode( MONO ),
618  mStereoBase( DEFAULT_STEREO_BASE ),
619  mSystemOverlay(NULL)
620 {
621 }
622 
624 {
625  return mUpdateManager;
626 }
627 
628 unsigned int* Stage::ReserveMessageSlot( std::size_t size, bool updateScene )
629 {
630  return mUpdateManager.ReserveMessageSlot( size, updateScene );
631 }
632 
634 {
636 }
637 
639 {
640  delete mSystemOverlay;
641 
643 }
644 
645 } // namespace Internal
646 
647 } // namespace Dali
Dali Docs Home
Read more about Dali