Merge branch 'devel/master' into tizen
[platform/core/uifw/dali-core.git] / dali / internal / event / render-tasks / render-task-impl.cpp
1 /*
2  * Copyright (c) 2015 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/render-tasks/render-task-impl.h>
20
21 // EXTERNAL INCLUDES
22 #include <cstring> // for strcmp
23
24 // INTERNAL INCLUDES
25 #include <dali/public-api/common/dali-common.h>
26 #include <dali/public-api/object/type-registry.h>
27 #include <dali/internal/event/common/event-thread-services.h>
28 #include <dali/internal/event/actors/actor-impl.h>
29 #include <dali/internal/event/actors/camera-actor-impl.h>
30 #include <dali/internal/event/common/property-helper.h>
31 #include <dali/internal/event/common/stage-impl.h>
32 #include <dali/internal/event/common/projection.h>
33 #include <dali/internal/event/images/frame-buffer-image-impl.h>
34 #include <dali/internal/update/nodes/node.h>
35 #include <dali/internal/event/render-tasks/render-task-list-impl.h>
36 #include <dali/internal/update/render-tasks/scene-graph-render-task.h>
37
38 #if defined(DEBUG_ENABLED)
39 namespace
40 {
41 Debug::Filter* gLogRender = Debug::Filter::New(Debug::Concise, false, "LOG_RENDER_TASK");
42 }
43 #endif
44
45 namespace Dali
46 {
47
48 namespace Internal
49 {
50
51 namespace // For internal properties
52 {
53
54 // Properties
55
56 //              Name                 Type     writable animatable constraint-input  enum for index-checking
57 DALI_PROPERTY_TABLE_BEGIN
58 DALI_PROPERTY( "viewportPosition",   VECTOR2,    true,    true,    true,    Dali::RenderTask::Property::VIEWPORT_POSITION )
59 DALI_PROPERTY( "viewportSize",       VECTOR2,    true,    true,    true,    Dali::RenderTask::Property::VIEWPORT_SIZE     )
60 DALI_PROPERTY( "clearColor",         VECTOR4,    true,    true,    true,    Dali::RenderTask::Property::CLEAR_COLOR       )
61 DALI_PROPERTY( "requiresSync",       BOOLEAN,    true,    false,   false,   Dali::RenderTask::Property::REQUIRES_SYNC     )
62 DALI_PROPERTY_TABLE_END( DEFAULT_OBJECT_PROPERTY_START_INDEX )
63
64 // Signals
65
66 const char* const SIGNAL_FINISHED = "finished";
67
68 TypeRegistration mType( typeid( Dali::RenderTask ), typeid( Dali::BaseHandle ), NULL );
69
70 SignalConnectorType signalConnector1( mType, SIGNAL_FINISHED, &RenderTask::DoConnectSignal );
71
72 } // Unnamed namespace
73
74 RenderTask* RenderTask::New( bool isSystemLevel )
75 {
76   RenderTask* task( new RenderTask( isSystemLevel ) );
77
78   return task;
79 }
80
81 void RenderTask::SetSourceActor( Actor* actor )
82 {
83   const Stage* stage = Stage::GetCurrent();
84   if ( stage )
85   {
86     stage->GetRenderTaskList().SetExclusive( this, mExclusive );
87   }
88   mSourceConnector.SetActor( actor );
89 }
90
91 Actor* RenderTask::GetSourceActor() const
92 {
93   return mSourceConnector.mActor;
94 }
95
96 void RenderTask::SetExclusive( bool exclusive )
97 {
98   if ( mExclusive != exclusive )
99   {
100     mExclusive = exclusive;
101
102     const Stage* stage = Stage::GetCurrent();
103     if ( stage )
104     {
105       stage->GetRenderTaskList().SetExclusive( this, exclusive );
106     }
107
108     if ( mSceneObject )
109     {
110       // mSceneObject is being used in a separate thread; queue a message to set the value
111       SetExclusiveMessage( GetEventThreadServices(), *mSceneObject, mExclusive );
112     }
113   }
114 }
115
116 bool RenderTask::IsExclusive() const
117 {
118   return mExclusive;
119 }
120
121 void RenderTask::SetInputEnabled( bool enabled )
122 {
123   mInputEnabled = enabled;
124 }
125
126 bool RenderTask::GetInputEnabled() const
127 {
128   return mInputEnabled;
129 }
130
131 void RenderTask::SetCameraActor( CameraActor* cameraActor )
132 {
133   mCameraConnector.SetActor( cameraActor );
134 }
135
136 CameraActor* RenderTask::GetCameraActor() const
137 {
138   // camera connector can only point to camera actor
139   return static_cast< CameraActor* >( mCameraConnector.mActor );
140 }
141
142 void RenderTask::SetTargetFrameBuffer( Dali::FrameBufferImage image )
143 {
144   if ( mFrameBufferImage != image )
145   {
146     // if we have a scene object we need to track connection status and set frame buffer id as well as updating target frame buffer
147     if ( mSceneObject )
148     {
149       if(mFrameBufferImage)
150       {
151         GetImplementation(mFrameBufferImage).Disconnect();
152       }
153
154       // update target frame buffer
155       mFrameBufferImage = image;
156
157       unsigned int resourceId = 0;
158       bool isNativeFBO = false;
159       if( mFrameBufferImage )
160       {
161         Dali::Internal::FrameBufferImage& impl = GetImplementation( mFrameBufferImage );
162         impl.Connect();
163         resourceId = impl.GetResourceId();
164         isNativeFBO = impl.IsNativeFbo();
165       }
166
167       // mSceneObject is being used in a separate thread; queue a message to set the value
168       SetFrameBufferIdMessage( GetEventThreadServices(), *mSceneObject, resourceId, isNativeFBO );
169     }
170     else
171     {
172       // update target frame buffer
173       mFrameBufferImage = image;
174     }
175   }
176 }
177
178 Dali::FrameBufferImage RenderTask::GetTargetFrameBuffer() const
179 {
180   return mFrameBufferImage;
181 }
182
183 void RenderTask::SetScreenToFrameBufferFunction( ScreenToFrameBufferFunction conversionFunction )
184 {
185   mScreenToFrameBufferFunction = conversionFunction;
186 }
187
188 RenderTask::ScreenToFrameBufferFunction RenderTask::GetScreenToFrameBufferFunction() const
189 {
190   return mScreenToFrameBufferFunction;
191 }
192
193 void RenderTask::SetScreenToFrameBufferMappingActor( Actor* mappingActor )
194 {
195   mMappingConnector.SetActor( mappingActor );
196 }
197
198 Actor* RenderTask::GetScreenToFrameBufferMappingActor() const
199 {
200   return mMappingConnector.mActor;
201 }
202
203 void RenderTask::SetViewportPosition(const Vector2& value)
204 {
205   BakeViewportPositionMessage( GetEventThreadServices(), *mSceneObject, value );
206 }
207
208 Vector2 RenderTask::GetCurrentViewportPosition() const
209 {
210   return mSceneObject->GetViewportPosition( GetEventThreadServices().GetEventBufferIndex() );
211 }
212
213 void RenderTask::SetViewportSize(const Vector2& value)
214 {
215   BakeViewportSizeMessage( GetEventThreadServices(), *mSceneObject, value );
216 }
217
218 Vector2 RenderTask::GetCurrentViewportSize() const
219 {
220   return mSceneObject->GetViewportSize( GetEventThreadServices().GetEventBufferIndex() );
221 }
222
223 void RenderTask::SetViewport( const Viewport& viewport )
224 {
225   SetViewportPosition(Vector2(viewport.x, viewport.y));
226   SetViewportSize(Vector2(viewport.width, viewport.height));
227 }
228
229 void RenderTask::GetViewport( Viewport& viewPort ) const
230 {
231   BufferIndex bufferIndex = GetEventThreadServices().GetEventBufferIndex();
232
233   if(!mSceneObject->GetViewportEnabled( bufferIndex ))
234   {
235     if ( mFrameBufferImage )
236     {
237       viewPort.x = viewPort.y = 0;
238       viewPort.width = mFrameBufferImage.GetWidth();
239       viewPort.height = mFrameBufferImage.GetHeight();
240     }
241     else
242     {
243       Internal::Stage* stage = Internal::Stage::GetCurrent();
244       if ( stage )
245       {
246         Vector2 size( stage->GetSize() );
247         viewPort.x = viewPort.y = 0;
248         viewPort.width = size.width;
249         viewPort.height = size.height;
250       }
251     }
252   }
253   else
254   {
255     const Vector2& position = mSceneObject->GetViewportPosition(bufferIndex);
256     const Vector2& size = mSceneObject->GetViewportSize(bufferIndex);
257     viewPort.x = position.x;
258     viewPort.y = position.y;
259     viewPort.width = size.width;
260     viewPort.height = size.height;
261   }
262 }
263
264 void RenderTask::SetClearColor( const Vector4& color )
265 {
266   if ( mClearColor != color )
267   {
268     mClearColor = color;
269
270     if ( mSceneObject )
271     {
272       // mSceneObject is being used in a separate thread; queue a message to set the value
273       BakeClearColorMessage( GetEventThreadServices(), *mSceneObject, color );
274     }
275   }
276 }
277
278 const Vector4& RenderTask::GetClearColor() const
279 {
280   return mSceneObject->GetClearColor( GetEventThreadServices().GetEventBufferIndex() );
281 }
282
283 void RenderTask::SetSyncRequired( bool requiresSync )
284 {
285   if( mRequiresSync != requiresSync )
286   {
287     mRequiresSync = requiresSync;
288
289     if( mSceneObject )
290     {
291       // mSceneObject is being used in a separate thread; queue a message to set the value
292       SetSyncRequiredMessage( GetEventThreadServices(), *mSceneObject, requiresSync );
293     }
294   }
295 }
296
297 bool RenderTask::IsSyncRequired() const
298 {
299   return mRequiresSync;
300 }
301
302 void RenderTask::SetClearEnabled( bool enabled )
303 {
304   if ( mClearEnabled != enabled )
305   {
306     mClearEnabled = enabled;
307
308     if ( mSceneObject )
309     {
310       // mSceneObject is being used in a separate thread; queue a message to set the value
311       SetClearEnabledMessage( GetEventThreadServices(), *mSceneObject, mClearEnabled );
312     }
313   }
314 }
315
316 bool RenderTask::GetClearEnabled() const
317 {
318   return mClearEnabled;
319 }
320
321 void RenderTask::SetCullMode( bool mode )
322 {
323   if ( mCullMode != mode )
324   {
325     mCullMode = mode;
326
327     if ( mSceneObject )
328     {
329       // mSceneObject is being used in a separate thread; queue a message to set the value
330       SetCullModeMessage( GetEventThreadServices(), *mSceneObject, mCullMode );
331     }
332   }
333 }
334
335 bool RenderTask::GetCullMode() const
336 {
337   return mCullMode;
338 }
339
340 void RenderTask::SetRefreshRate( unsigned int refreshRate )
341 {
342   DALI_LOG_TRACE_METHOD_FMT(gLogRender, "this:%p  rate:%d\n", this, refreshRate);
343   DALI_LOG_INFO(gLogRender, Debug::General, "RenderTask::SetRefreshRate(this:%p, %d)\n", this, refreshRate);
344
345   mRefreshRate = refreshRate; // cached for GetRefreshRate()
346
347   // Note - even when refreshRate is the same as mRefreshRate, a message should be sent
348
349   if ( mSceneObject )
350   {
351     // mSceneObject is being used in a separate thread; queue a message to set the value
352     SetRefreshRateMessage( GetEventThreadServices(), *mSceneObject, refreshRate );
353   }
354 }
355
356 unsigned int RenderTask::GetRefreshRate() const
357 {
358   return mRefreshRate;
359 }
360
361 bool RenderTask::IsHittable( Vector2& screenCoords ) const
362 {
363   // True when input is enabled, source & camera actor are valid
364   bool inputEnabled( false );
365
366   Actor* sourceActor = GetSourceActor();
367   CameraActor* cameraActor = GetCameraActor();
368
369   if ( mInputEnabled  &&
370        NULL != sourceActor    &&
371        sourceActor->OnStage() &&
372        NULL != cameraActor    &&
373        cameraActor->OnStage() )
374   {
375     // If the actors are rendered off-screen, then the screen coordinates must be converted
376     // and the conversion function will tell us if they are inside or outside
377     if ( TranslateCoordinates( screenCoords ) )
378     {
379       // This is a suitable render-task for input handling
380       inputEnabled = true;
381     }
382   }
383
384   return inputEnabled;
385 }
386
387 bool RenderTask::TranslateCoordinates( Vector2& screenCoords ) const
388 {
389   // return true for on-screen tasks
390   bool inside( true );
391   // If the actors are rendered off-screen, then the screen coordinates must be converted
392   // the function should only be called for offscreen tasks
393   if( mFrameBufferImage && mMappingConnector.mActor )
394   {
395     CameraActor* localCamera = GetCameraActor();
396     StagePtr stage = Stage::GetCurrent();
397     if( stage )
398     {
399       CameraActor& defaultCamera = stage->GetDefaultCameraActor();
400       if( localCamera )
401       {
402         Viewport viewport;
403         Vector2 size( stage->GetSize() );
404         viewport.x = viewport.y = 0;
405         viewport.width = size.width;
406         viewport.height = size.height;
407
408         float localX, localY;
409         inside = mMappingConnector.mActor->ScreenToLocal(defaultCamera.GetViewMatrix(), defaultCamera.GetProjectionMatrix(), viewport, localX, localY, screenCoords.x, screenCoords.y);
410         Vector3 actorSize = mMappingConnector.mActor->GetCurrentSize();
411         if( inside && localX >= 0.f && localX <= actorSize.x && localY >= 0.f && localY <= actorSize.y)
412         {
413           screenCoords.x = localX;
414           screenCoords.y = localY;
415         }
416         else
417         {
418           inside = false;
419         }
420       }
421       else
422       {
423         inside = false;
424       }
425     }
426   }
427   else if ( mFrameBufferImage && mScreenToFrameBufferFunction )
428   {
429     inside = mScreenToFrameBufferFunction( screenCoords );
430   }
431   return inside;
432 }
433
434 bool RenderTask::IsSystemLevel() const
435 {
436   return mIsSystemLevel;
437 }
438
439 bool RenderTask::WorldToViewport(const Vector3 &position, float& viewportX, float& viewportY) const
440 {
441   CameraActor* cam = GetCameraActor();
442
443   Vector4 pos(position);
444   pos.w = 1.0;
445
446   Vector4 viewportPosition;
447
448   Viewport viewport;
449   GetViewport( viewport );
450
451   bool ok = ProjectFull(pos,
452                         cam->GetViewMatrix(),
453                         cam->GetProjectionMatrix(),
454                         viewport.x,
455                         viewport.y,
456                         viewport.width,
457                         viewport.height,
458                         viewportPosition);
459   if(ok)
460   {
461     viewportX = viewportPosition.x;
462     viewportY = viewportPosition.y;
463   }
464
465   return ok;
466 }
467
468 bool RenderTask::ViewportToLocal(Actor* actor, float viewportX, float viewportY, float &localX, float &localY) const
469 {
470   return actor->ScreenToLocal( *this, localX, localY, viewportX, viewportY );
471 }
472
473 SceneGraph::RenderTask* RenderTask::CreateSceneObject()
474 {
475   // This should only be called once, with no existing scene-object
476   DALI_ASSERT_DEBUG( NULL == mSceneObject );
477
478   // Keep the raw-pointer until DiscardSceneObject is called
479   mSceneObject = SceneGraph::RenderTask::New();
480
481   // if we have a frame buffer we need to track connection status then send a message to set the frame buffer id in case it has changed since last time we were on stage
482   unsigned int resourceId = 0;
483   bool isNativeFBO = false;
484   if( mFrameBufferImage )
485   {
486     Dali::Internal::FrameBufferImage& impl = GetImplementation( mFrameBufferImage );
487     impl.Connect();
488     resourceId = impl.GetResourceId();
489     isNativeFBO = impl.IsNativeFbo();
490   }
491
492   // mSceneObject is being used in a separate thread; queue a message to set the value
493   SetFrameBufferIdMessage( GetEventThreadServices(), *mSceneObject, resourceId, isNativeFBO );
494
495   // Send messages to set other properties that may have changed since last time we were on stage
496   SetExclusiveMessage( GetEventThreadServices(), *mSceneObject, mExclusive );
497   SetClearColorMessage(  GetEventThreadServices(), *mSceneObject, mClearColor );
498   SetClearEnabledMessage(  GetEventThreadServices(), *mSceneObject, mClearEnabled );
499   SetCullModeMessage(  GetEventThreadServices(), *mSceneObject, mCullMode );
500   SetRefreshRateMessage(  GetEventThreadServices(), *mSceneObject, mRefreshRate );
501
502   // Caller takes ownership
503   return mSceneObject;
504 }
505
506 SceneGraph::RenderTask* RenderTask::GetRenderTaskSceneObject()
507 {
508   return mSceneObject;
509 }
510
511 void RenderTask::DiscardSceneObject()
512 {
513   // mSceneObject is not owned; throw away the raw-pointer
514   mSceneObject = NULL;
515
516   // if we have a frame buffer we need to track connection status
517   if(mFrameBufferImage)
518   {
519     GetImplementation(mFrameBufferImage).Disconnect();
520   }
521 }
522
523 /********************************************************************************
524  ********************************   PROPERTY METHODS   **************************
525  ********************************************************************************/
526
527 unsigned int RenderTask::GetDefaultPropertyCount() const
528 {
529   return DEFAULT_PROPERTY_COUNT;
530 }
531
532 void RenderTask::GetDefaultPropertyIndices( Property::IndexContainer& indices ) const
533 {
534   indices.Reserve( DEFAULT_PROPERTY_COUNT );
535
536   for ( int i = 0; i < DEFAULT_PROPERTY_COUNT; ++i )
537   {
538     indices.PushBack( i );
539   }
540 }
541
542 const char* RenderTask::GetDefaultPropertyName( Property::Index index ) const
543 {
544   if( index < DEFAULT_PROPERTY_COUNT )
545   {
546     return DEFAULT_PROPERTY_DETAILS[index].name;
547   }
548   else
549   {
550     return NULL;
551   }
552 }
553
554 Property::Index RenderTask::GetDefaultPropertyIndex(const std::string& name) const
555 {
556   Property::Index index = Property::INVALID_INDEX;
557
558   // Look for name in default properties
559   for( int i = 0; i < DEFAULT_PROPERTY_COUNT; ++i )
560   {
561     if( 0 == strcmp( name.c_str(), DEFAULT_PROPERTY_DETAILS[i].name ) ) // dont want to convert rhs to string
562     {
563       index = i;
564       break;
565     }
566   }
567
568   return index;
569 }
570
571 bool RenderTask::IsDefaultPropertyWritable(Property::Index index) const
572 {
573   return DEFAULT_PROPERTY_DETAILS[ index ].writable;
574 }
575
576 bool RenderTask::IsDefaultPropertyAnimatable(Property::Index index) const
577 {
578   return DEFAULT_PROPERTY_DETAILS[ index ].animatable;
579 }
580
581 bool RenderTask::IsDefaultPropertyAConstraintInput( Property::Index index ) const
582 {
583   return DEFAULT_PROPERTY_DETAILS[ index ].constraintInput;
584 }
585
586 Property::Type RenderTask::GetDefaultPropertyType(Property::Index index) const
587 {
588   if( index < DEFAULT_PROPERTY_COUNT )
589   {
590     return DEFAULT_PROPERTY_DETAILS[index].type;
591   }
592
593   // index out of range...return Property::NONE
594   return Property::NONE;
595 }
596
597 void RenderTask::SetDefaultProperty( Property::Index index, const Property::Value& property )
598 {
599   switch ( index )
600   {
601     case Dali::RenderTask::Property::VIEWPORT_POSITION:
602     {
603       SetViewportPosition( property.Get<Vector2>() );
604       break;
605     }
606     case Dali::RenderTask::Property::VIEWPORT_SIZE:
607     {
608       SetViewportSize( property.Get<Vector2>() );
609       break;
610     }
611     case Dali::RenderTask::Property::CLEAR_COLOR:
612     {
613       SetClearColor( property.Get<Vector4>() );
614       break;
615     }
616     case Dali::RenderTask::Property::REQUIRES_SYNC:
617     {
618       SetSyncRequired( property.Get<bool>() );
619       break;
620     }
621     default:
622     {
623       // nothing to do
624       break;
625     }
626   }
627 }
628
629 Property::Value RenderTask::GetDefaultProperty(Property::Index index) const
630 {
631   Property::Value value;
632
633   switch ( index )
634   {
635
636     case Dali::RenderTask::Property::VIEWPORT_POSITION:
637     {
638       value = GetCurrentViewportPosition();
639       break;
640     }
641     case Dali::RenderTask::Property::VIEWPORT_SIZE:
642     {
643       value = GetCurrentViewportSize();
644       break;
645     }
646     case Dali::RenderTask::Property::CLEAR_COLOR:
647     {
648       value = GetClearColor();
649       break;
650     }
651     case Dali::RenderTask::Property::REQUIRES_SYNC:
652     {
653       value = IsSyncRequired();
654       break;
655     }
656
657     default:
658     {
659       DALI_ASSERT_ALWAYS(false && "RenderTask property index out of range"); // should not come here
660       break;
661     }
662   }
663
664   return value;
665 }
666
667 const SceneGraph::PropertyOwner* RenderTask::GetSceneObject() const
668 {
669   return mSceneObject;
670 }
671
672 const SceneGraph::PropertyBase* RenderTask::GetSceneObjectAnimatableProperty( Property::Index index ) const
673 {
674   DALI_ASSERT_ALWAYS( IsPropertyAnimatable(index) && "Property is not animatable" );
675
676   const SceneGraph::PropertyBase* property( NULL );
677
678   // This method should only return a property which is part of the scene-graph
679   if( mSceneObject != NULL )
680   {
681     switch ( index )
682     {
683       case Dali::RenderTask::Property::VIEWPORT_POSITION:
684         property = &mSceneObject->mViewportPosition;
685         break;
686
687       case Dali::RenderTask::Property::VIEWPORT_SIZE:
688         property = &mSceneObject->mViewportSize;
689         break;
690
691       case Dali::RenderTask::Property::CLEAR_COLOR:
692         property = &mSceneObject->mClearColor;
693         break;
694
695       default:
696         break;
697     }
698   }
699
700   return property;
701 }
702
703 const PropertyInputImpl* RenderTask::GetSceneObjectInputProperty( Property::Index index ) const
704 {
705   const PropertyInputImpl* property( NULL );
706   if( mSceneObject != NULL )
707   {
708     switch ( index )
709     {
710       case Dali::RenderTask::Property::VIEWPORT_POSITION:
711         property = &mSceneObject->mViewportPosition;
712         break;
713
714       case Dali::RenderTask::Property::VIEWPORT_SIZE:
715         property = &mSceneObject->mViewportSize;
716         break;
717
718       case Dali::RenderTask::Property::CLEAR_COLOR:
719         property = &mSceneObject->mClearColor;
720         break;
721
722       default:
723         break;
724     }
725   }
726
727   return property;
728 }
729
730 bool RenderTask::HasFinished()
731 {
732   bool finished = false;
733   const unsigned int counter = mSceneObject->GetRenderedOnceCounter();
734
735   if( mRefreshOnceCounter < counter )
736   {
737     finished = true;
738     mRefreshOnceCounter = counter;
739   }
740
741   DALI_LOG_INFO(gLogRender, Debug::General, "RenderTask::HasFinished()=%s SCRT:%p  SC\n", finished?"T":"F", mSceneObject);
742
743   return finished;
744 }
745
746 void RenderTask::EmitSignalFinish()
747 {
748   DALI_LOG_INFO(gLogRender, Debug::General, "RenderTask::EmitSignalFinish(this:%p)\n", this);
749
750   if( !mSignalFinished.Empty() )
751   {
752     Dali::RenderTask handle( this );
753     mSignalFinished.Emit(handle );
754   }
755 }
756
757 Dali::RenderTask::RenderTaskSignalType& RenderTask::FinishedSignal()
758 {
759   return mSignalFinished;
760 }
761
762 bool RenderTask::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor )
763 {
764   bool connected( true );
765   RenderTask* renderTask = dynamic_cast<RenderTask*>(object);
766
767   if ( 0 == strcmp( signalName.c_str(), SIGNAL_FINISHED ) )
768   {
769     renderTask->FinishedSignal().Connect( tracker, functor );
770   }
771   else
772   {
773     // signalName does not match any signal
774     connected = false;
775   }
776
777   return connected;
778 }
779
780 RenderTask::RenderTask( bool isSystemLevel )
781 : mSceneObject( NULL ),
782   mSourceConnector( Connector::SOURCE_CONNECTOR, *this ),
783   mCameraConnector( Connector::CAMERA_CONNECTOR, *this ),
784   mMappingConnector( Connector::MAPPING_CONNECTOR, *this  ),
785   mClearColor( Dali::RenderTask::DEFAULT_CLEAR_COLOR ),
786   mRefreshRate( Dali::RenderTask::DEFAULT_REFRESH_RATE ),
787   mRefreshOnceCounter( 0u ),
788   mScreenToFrameBufferFunction( Dali::RenderTask::DEFAULT_SCREEN_TO_FRAMEBUFFER_FUNCTION ),
789   mExclusive( Dali::RenderTask::DEFAULT_EXCLUSIVE ),
790   mInputEnabled( Dali::RenderTask::DEFAULT_INPUT_ENABLED ),
791   mClearEnabled( Dali::RenderTask::DEFAULT_CLEAR_ENABLED ),
792   mCullMode( Dali::RenderTask::DEFAULT_CULL_MODE ),
793   mIsSystemLevel( isSystemLevel ),
794   mRequiresSync( false )
795 {
796   DALI_LOG_INFO(gLogRender, Debug::General, "RenderTask::RenderTask(this:%p)\n", this);
797 }
798
799 RenderTask::~RenderTask()
800 {
801   DALI_LOG_INFO(gLogRender, Debug::General, "RenderTask::~RenderTask(this:%p)\n", this);
802 }
803
804 // Helper class for connecting Nodes to the scene-graph RenderTask
805
806 RenderTask::Connector::Connector( Type type, RenderTask& renderTask )
807 : mType( type ),
808   mRenderTask( renderTask ),
809   mActor( NULL )
810 {
811 }
812
813 RenderTask::Connector::~Connector()
814 {
815   SetActor( NULL );
816 }
817
818 void RenderTask::Connector::SetActor( Actor* actor )
819 {
820   if ( mActor != actor )
821   {
822     if ( mActor )
823     {
824       mActor->RemoveObserver( *this );
825     }
826
827     mActor = actor;
828
829     if ( mActor )
830     {
831       mActor->AddObserver( *this );
832     }
833
834     UpdateRenderTask();
835   }
836 }
837
838 void RenderTask::Connector::SceneObjectAdded( Object& object )
839 {
840   UpdateRenderTask();
841 }
842
843 void RenderTask::Connector::SceneObjectRemoved( Object& object )
844 {
845   UpdateRenderTask();
846 }
847
848 void RenderTask::Connector::ObjectDestroyed( Object& object )
849 {
850   if ( SOURCE_CONNECTOR == mType )
851   {
852     const Stage* stage = Stage::GetCurrent();
853     if ( stage )
854     {
855       stage->GetRenderTaskList().SetExclusive( &mRenderTask, false );
856     }
857   }
858
859   mActor = NULL;
860
861   UpdateRenderTask();
862 }
863
864 void RenderTask::Connector::UpdateRenderTask()
865 {
866   // Guard to allow handle destruction after Core has been destroyed
867   if( Internal::Stage::IsInstalled() &&
868       mRenderTask.mSceneObject )
869   {
870     const SceneGraph::Node* node( NULL );
871
872     // Check whether a Node exists in the scene-graph
873     if ( NULL != mActor )
874     {
875       const SceneGraph::PropertyOwner* object = mActor->GetSceneObject();
876       if ( NULL != object )
877       {
878         // actors only point to nodes as their scene objects
879         node = static_cast< const SceneGraph::Node* >( object );
880       }
881     }
882
883     //the mapping node is not used in the scene graph
884     if ( SOURCE_CONNECTOR == mType )
885     {
886       SetSourceNodeMessage( mRenderTask.GetEventThreadServices(), *(mRenderTask.mSceneObject), node );
887     }
888     else if( CAMERA_CONNECTOR == mType )
889     {
890       SetCameraNodeMessage( mRenderTask.GetEventThreadServices(), *(mRenderTask.mSceneObject), node );
891     }
892   }
893 }
894
895 } // namespace Internal
896
897 } // namespace Dali