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