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