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