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