Type registry helper: Toolkit change to correct Programming Guide for Custom Controls
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / controls / effects-view / effects-view-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 "effects-view-impl.h"
20
21 // EXTERNAL INCLUDES
22 #include <dali/public-api/animation/constraint.h>
23 #include <dali/public-api/animation/constraints.h>
24 #include <dali/public-api/common/stage.h>
25 #include <dali/public-api/object/property-map.h>
26 #include <dali/public-api/object/type-registry.h>
27 #include <dali/public-api/object/type-registry-helper.h>
28 #include <dali/public-api/render-tasks/render-task-list.h>
29
30 // INTERNAL INCLUDES
31 #include <dali-toolkit/devel-api/controls/control-depth-index-ranges.h>
32 #include <dali-toolkit/internal/filters/blur-two-pass-filter.h>
33 #include <dali-toolkit/internal/filters/emboss-filter.h>
34 #include <dali-toolkit/internal/filters/spread-filter.h>
35
36 namespace Dali
37 {
38
39 namespace Toolkit
40 {
41
42 namespace Internal
43 {
44
45 namespace
46 {
47
48 Dali::BaseHandle Create()
49 {
50   return EffectsView::New();
51 }
52
53 DALI_TYPE_REGISTRATION_BEGIN( Toolkit::EffectsView, Toolkit::Control, Create )
54 DALI_PROPERTY_REGISTRATION( Toolkit, EffectsView, "effectSize", INTEGER, EFFECT_SIZE )
55 DALI_ANIMATABLE_PROPERTY_REGISTRATION( Toolkit, EffectsView, "effectOffset", VECTOR3, EFFECT_OFFSET )
56 DALI_ANIMATABLE_PROPERTY_REGISTRATION_WITH_DEFAULT( Toolkit, EffectsView, "effectColor", Color::WHITE, EFFECT_COLOR )
57 DALI_TYPE_REGISTRATION_END()
58
59 const Pixel::Format EFFECTS_VIEW_DEFAULT_PIXEL_FORMAT = Pixel::RGBA8888;
60 const float         ARBITRARY_FIELD_OF_VIEW = Math::PI / 4.0f;
61 const Vector4       EFFECTS_VIEW_DEFAULT_BACKGROUND_COLOR( 1.0f, 1.0f, 1.0f, 0.0 );
62 const bool          EFFECTS_VIEW_REFRESH_ON_DEMAND(false);
63
64 const char* EFFECTS_VIEW_VERTEX_SOURCE = DALI_COMPOSE_SHADER(
65   attribute mediump vec2 aPosition;\n
66   varying mediump vec2 vTexCoord;\n
67   uniform mediump mat4 uMvpMatrix;\n
68   uniform mediump vec3 uSize;\n
69   uniform mediump vec3 effectOffset;\n
70   \n
71   void main()\n
72   {\n
73     mediump vec4 vertexPosition = vec4(aPosition, 0.0, 1.0);\n
74     vertexPosition.xyz *= uSize;\n
75     vertexPosition.xyz += effectOffset;\n
76     vertexPosition = uMvpMatrix * vertexPosition;\n
77     \n
78     vTexCoord = aPosition + vec2(0.5);\n
79     gl_Position = vertexPosition;\n
80   }\n
81 );
82
83 const char* EFFECTS_VIEW_FRAGMENT_SOURCE = DALI_COMPOSE_SHADER(
84   varying mediump vec2 vTexCoord;\n
85   uniform sampler2D sTexture;\n
86   uniform lowp vec4 effectColor;\n
87   \n
88   void main()\n
89   {\n
90      gl_FragColor = effectColor;\n
91      gl_FragColor.a *= texture2D( sTexture, vTexCoord).a;\n
92   }\n
93 );
94
95 const float BLUR_KERNEL0[] = { 12.0f/16.0f,
96                                2.0f/16.0f, 2.0f/16.0f };
97
98 const float BLUR_KERNEL1[] = { 8.0f/16.0f,
99                                4.0f/16.0f, 4.0f/16.0f };
100
101 const float BLUR_KERNEL2[] = { 6.0f/16.0f,
102                                2.5f/16.0f, 2.5f/16.0f,
103                                1.5f/16.0f, 1.5f/16.0f,
104                                1.0f/16.0f, 1.0f/16.0f };
105
106 const float BLUR_KERNEL3[] = { 4.0f/16.0f,
107                                3.0f/16.0f, 2.0f/16.0f,
108                                2.0f/16.0f, 2.0f/16.0f,
109                                1.0f/16.0f, 1.0f/16.0f };
110
111 const float BLUR_KERNEL4[] = { 3.0f/16.0f,
112                                2.5f/16.0f,  2.5f/16.0f,
113                                1.75f/16.0f, 1.75f/16.0f,
114                                1.25f/16.0f, 1.25f/16.0f,
115                                1.0f/16.0f,  1.0f/16.0f };
116
117 } // namespace
118
119 Toolkit::EffectsView EffectsView::New()
120 {
121   EffectsView* effectsView = new EffectsView;
122
123   Toolkit::EffectsView handle = Toolkit::EffectsView( *effectsView );
124
125   // Second-phase init of the implementation
126   // This can only be done after the CustomActor connection has been made...
127   effectsView->Initialize();
128
129   return handle;
130 }
131
132 EffectsView::EffectsView()
133 : Control( ControlBehaviour( ACTOR_BEHAVIOUR_NONE ) ),
134   mChildrenRoot(Actor::New()),
135   mBackgroundColor( EFFECTS_VIEW_DEFAULT_BACKGROUND_COLOR ),
136   mTargetSize( Vector2::ZERO ),
137   mLastSize( Vector2::ZERO ),
138   mEffectSize(0),
139   mEffectType( Toolkit::EffectsView::INVALID_TYPE ),
140   mPixelFormat( EFFECTS_VIEW_DEFAULT_PIXEL_FORMAT ),
141   mEnabled( false ),
142   mRefreshOnDemand(EFFECTS_VIEW_REFRESH_ON_DEMAND)
143 {
144 }
145
146 EffectsView::~EffectsView()
147 {
148   RemoveFilters();
149 }
150
151 void EffectsView::SetType( Toolkit::EffectsView::EffectType type )
152 {
153   if( mEffectType != type )
154   {
155     RemoveFilters();
156
157     Actor self = Self();
158     Property::Map rendererMap;
159     rendererMap.Insert( "rendererType", "image" );
160
161     switch( type )
162     {
163       case Toolkit::EffectsView::DROP_SHADOW:
164       {
165         mFilters.PushBack( new SpreadFilter );
166         mFilters.PushBack( new BlurTwoPassFilter );
167         break;
168       }
169       case Toolkit::EffectsView::EMBOSS:
170       {
171         mFilters.PushBack( new SpreadFilter );
172         mFilters.PushBack( new EmbossFilter );
173         mFilters.PushBack( new BlurTwoPassFilter );
174         break;
175       }
176       default:
177       {
178         break;
179       }
180     }
181
182     Property::Map customShader;
183     customShader[ "vertexShader" ] = EFFECTS_VIEW_VERTEX_SOURCE;
184     customShader[ "fragmentShader" ] = EFFECTS_VIEW_FRAGMENT_SOURCE;
185     rendererMap[ "shader" ] = customShader;
186     Toolkit::RendererFactory::Get().ResetRenderer( mRendererPostFilter, self, rendererMap );
187
188     mEffectType = type;
189   }
190 }
191
192 Toolkit::EffectsView::EffectType EffectsView::GetType() const
193 {
194   return mEffectType;
195 }
196
197 void EffectsView::Enable()
198 {
199   // make sure resources are allocated and start the render tasks processing
200   AllocateResources();
201   CreateRenderTasks();
202   mEnabled = true;
203 }
204
205 void EffectsView::Disable()
206 {
207   // stop render tasks processing
208   // Note: render target resources are automatically freed since we set the Image::Unused flag
209   RemoveRenderTasks();
210   mEnabled = false;
211 }
212
213 void EffectsView::Refresh()
214 {
215   RefreshRenderTasks();
216 }
217
218 void EffectsView::SetRefreshOnDemand( bool onDemand )
219 {
220   mRefreshOnDemand = onDemand;
221
222   RefreshRenderTasks();
223 }
224
225 void EffectsView::SetPixelFormat( Pixel::Format pixelFormat )
226 {
227   mPixelFormat = pixelFormat;
228 }
229
230 void EffectsView::SetBackgroundColor( const Vector4& color )
231 {
232   mBackgroundColor = color;
233 }
234
235 Vector4 EffectsView::GetBackgroundColor() const
236 {
237   return mBackgroundColor;
238 }
239
240 void EffectsView::SetEffectSize( int effectSize )
241 {
242   mEffectSize = effectSize;
243
244   if( mEnabled )
245   {
246     const size_t numFilters( mFilters.Size() );
247     for( size_t i = 0; i < numFilters; ++i )
248     {
249       mFilters[i]->Disable();
250     }
251
252     SetupFilters();
253
254     for( size_t i = 0; i < numFilters; ++i )
255     {
256       mFilters[i]->Enable();
257     }
258   }
259 }
260
261 int EffectsView::GetEffectSize()
262 {
263   return mEffectSize;
264 }
265
266 // From Control
267 void EffectsView::OnInitialize()
268 {
269   CustomActor self = Self();
270   mChildrenRoot.SetParentOrigin( ParentOrigin::CENTER );
271   self.Add( mChildrenRoot );
272 }
273
274 void EffectsView::OnSizeSet(const Vector3& targetSize)
275 {
276   Control::OnSizeSet( targetSize );
277
278   mTargetSize = Vector2(targetSize);
279
280   // if we are already on stage, need to update render target sizes now to reflect the new size of this actor
281   if(mEnabled)
282   {
283     if( mLastSize != Vector2::ZERO )
284     {
285       Disable();
286     }
287     Enable();
288   }
289
290   mChildrenRoot.SetSize( targetSize );
291 }
292
293 void EffectsView::OnStageConnection( int depth )
294 {
295   Control::OnStageConnection( depth );
296
297   Enable();
298
299   Actor self = Self();
300   if( mRendererPostFilter )
301   {
302     mRendererPostFilter.SetOnStage( self );
303   }
304   if( mRendererForChildren )
305   {
306     mRendererForChildren.SetOnStage( self );
307   }
308 }
309
310 void EffectsView::OnStageDisconnection()
311 {
312   Disable();
313
314   const size_t numFilters( mFilters.Size() );
315   for( size_t i = 0; i < numFilters; ++i )
316   {
317     mFilters[i]->Disable();
318   }
319
320   Actor self = Self();
321   if( mRendererPostFilter )
322   {
323     mRendererPostFilter.SetOffStage( self );
324   }
325   if( mRendererForChildren )
326   {
327     mRendererForChildren.SetOffStage( self );
328   }
329
330   Control::OnStageDisconnection();
331 }
332
333 void EffectsView::OnChildAdd( Actor& child )
334 {
335   Control::OnChildAdd( child );
336
337   if( child != mChildrenRoot && child != mCameraForChildren )
338   {
339     mChildrenRoot.Add( child );
340   }
341 }
342
343 void EffectsView::OnChildRemove( Actor& child )
344 {
345   mChildrenRoot.Remove( child );
346
347   Control::OnChildRemove( child );
348 }
349
350 void EffectsView::SetupFilters()
351 {
352   switch( mEffectType )
353   {
354     case Toolkit::EffectsView::DROP_SHADOW:
355     {
356       SpreadFilter* spreadFilter = static_cast< SpreadFilter* >( mFilters[0] );
357       spreadFilter->SetInputImage( mImageForChildren );
358       spreadFilter->SetOutputImage( mImagePostFilter );
359       spreadFilter->SetRootActor( mChildrenRoot );
360       spreadFilter->SetBackgroundColor( mBackgroundColor );
361       spreadFilter->SetPixelFormat( mPixelFormat );
362       spreadFilter->SetSize( mTargetSize );
363       spreadFilter->SetSpread( mEffectSize );
364
365       BlurTwoPassFilter* blurFilter = static_cast< BlurTwoPassFilter* >( mFilters[1] );
366       blurFilter->SetInputImage( mImagePostFilter );
367       blurFilter->SetOutputImage( mImagePostFilter );
368       blurFilter->SetRootActor( mChildrenRoot );
369       blurFilter->SetBackgroundColor( mBackgroundColor );
370       blurFilter->SetPixelFormat( mPixelFormat );
371       blurFilter->SetSize( mTargetSize );
372
373       const float* kernel(NULL);
374       size_t kernelSize(0);
375       switch( mEffectSize )
376       {
377         case 4:  {  kernel = BLUR_KERNEL4; kernelSize = sizeof(BLUR_KERNEL4)/sizeof(BLUR_KERNEL4[0]); break; }
378         case 3:  {  kernel = BLUR_KERNEL3; kernelSize = sizeof(BLUR_KERNEL3)/sizeof(BLUR_KERNEL3[0]); break; }
379         case 2:  {  kernel = BLUR_KERNEL2; kernelSize = sizeof(BLUR_KERNEL2)/sizeof(BLUR_KERNEL2[0]); break; }
380         case 1:  {  kernel = BLUR_KERNEL1; kernelSize = sizeof(BLUR_KERNEL1)/sizeof(BLUR_KERNEL1[0]); break; }
381         case 0:
382         default: {  kernel = BLUR_KERNEL0; kernelSize = sizeof(BLUR_KERNEL0)/sizeof(BLUR_KERNEL0[0]); break; }
383       }
384       blurFilter->CreateKernel( kernel, kernelSize );
385       break;
386     }
387     case Toolkit::EffectsView::EMBOSS:
388     {
389       SpreadFilter* spreadFilter = static_cast< SpreadFilter* >( mFilters[0] );
390       spreadFilter->SetInputImage( mImageForChildren );
391       spreadFilter->SetOutputImage( mImagePostFilter );
392       spreadFilter->SetRootActor( mChildrenRoot );
393       spreadFilter->SetBackgroundColor( mBackgroundColor );
394       spreadFilter->SetPixelFormat( Pixel::RGBA8888 );
395       spreadFilter->SetSize( mTargetSize );
396       spreadFilter->SetSpread( mEffectSize );
397
398       EmbossFilter* embossFilter = static_cast< EmbossFilter* >( mFilters[1] );
399       embossFilter->SetInputImage( mImagePostFilter );
400       embossFilter->SetOutputImage( mImagePostFilter );
401       embossFilter->SetRootActor( mChildrenRoot );
402       embossFilter->SetBackgroundColor( mBackgroundColor );
403       embossFilter->SetPixelFormat( Pixel::RGBA8888 );
404       embossFilter->SetSize( mTargetSize );
405
406       BlurTwoPassFilter* blurFilter = static_cast< BlurTwoPassFilter* >( mFilters[2] );
407       blurFilter->SetInputImage( mImagePostFilter );
408       blurFilter->SetOutputImage( mImagePostFilter );
409       blurFilter->SetRootActor( mChildrenRoot );
410       blurFilter->SetBackgroundColor( Vector4( 0.5f, 0.5f, 0.5f, 0.0 ) );
411       blurFilter->SetPixelFormat( Pixel::RGBA8888 );
412       blurFilter->SetSize( mTargetSize );
413       blurFilter->CreateKernel( BLUR_KERNEL0, sizeof(BLUR_KERNEL0)/sizeof(BLUR_KERNEL0[0]) );
414
415       break;
416     }
417     default:
418     {
419       break;
420     }
421   }
422 }
423 void EffectsView::AllocateResources()
424 {
425   if(mTargetSize != mLastSize)
426   {
427     mLastSize = mTargetSize;
428     SetupCameras();
429
430     Toolkit::RendererFactory rendererFactory = Toolkit::RendererFactory::Get();
431     Actor self = Self();
432
433     mImageForChildren = FrameBufferImage::New( mTargetSize.width, mTargetSize.height, mPixelFormat, Dali::Image::UNUSED );
434     rendererFactory.ResetRenderer(mRendererForChildren, self, mImageForChildren);
435     mRendererForChildren.SetDepthIndex( DepthIndex::CONTENT+1 );
436
437     mImagePostFilter = FrameBufferImage::New( mTargetSize.width, mTargetSize.height, mPixelFormat, Dali::Image::UNUSED );
438     rendererFactory.ResetRenderer(mRendererPostFilter, self, mImagePostFilter);
439     mRendererPostFilter.SetDepthIndex( DepthIndex::CONTENT );
440
441     SetupFilters();
442   }
443 }
444
445 void EffectsView::SetupCameras()
446 {
447   if( !mCameraForChildren )
448   {
449     // Create a camera for the children render, corresponding to its render target size
450     mCameraForChildren = CameraActor::New(mTargetSize);
451     mCameraForChildren.SetParentOrigin(ParentOrigin::CENTER);
452     mCameraForChildren.SetInvertYAxis( true );
453     Self().Add( mCameraForChildren );
454   }
455   else
456   {
457     // place the camera for the children render, corresponding to its render target size
458     const float cameraPosScale( 0.5f / tanf(ARBITRARY_FIELD_OF_VIEW * 0.5f) );
459     mCameraForChildren.SetFieldOfView(ARBITRARY_FIELD_OF_VIEW);
460     mCameraForChildren.SetNearClippingPlane(1.0f);
461     mCameraForChildren.SetAspectRatio(mTargetSize.width / mTargetSize.height);
462     mCameraForChildren.SetType(Dali::Camera::FREE_LOOK); // camera orientation based solely on actor
463     mCameraForChildren.SetPosition(0.0f, 0.0f, mTargetSize.height * cameraPosScale);
464     mCameraForChildren.SetZ( mTargetSize.height * cameraPosScale );
465   }
466 }
467
468 void EffectsView::CreateRenderTasks()
469 {
470   if( mTargetSize == Vector2::ZERO )
471   {
472     return;
473   }
474   RenderTaskList taskList = Stage::GetCurrent().GetRenderTaskList();
475
476   // create render task to render our child actors to offscreen buffer
477   mRenderTaskForChildren = taskList.CreateTask();
478   mRenderTaskForChildren.SetRefreshRate( mRefreshOnDemand ? RenderTask::REFRESH_ONCE : RenderTask::REFRESH_ALWAYS );
479   mRenderTaskForChildren.SetSourceActor( mChildrenRoot );
480   mRenderTaskForChildren.SetExclusive(true);
481   mRenderTaskForChildren.SetInputEnabled( false );
482   mRenderTaskForChildren.SetClearColor( mBackgroundColor );
483   mRenderTaskForChildren.SetClearEnabled( true );
484   mRenderTaskForChildren.SetTargetFrameBuffer( mImageForChildren );
485   mRenderTaskForChildren.SetCameraActor(mCameraForChildren); // use camera that covers render target exactly
486
487   // Enable image filters
488   const size_t numFilters( mFilters.Size() );
489   for( size_t i = 0; i < numFilters; ++i )
490   {
491     mFilters[i]->Enable();
492   }
493 }
494
495 void EffectsView::RemoveRenderTasks()
496 {
497   if( mTargetSize == Vector2::ZERO )
498   {
499     return;
500   }
501
502   RenderTaskList taskList = Stage::GetCurrent().GetRenderTaskList();
503
504   taskList.RemoveTask(mRenderTaskForChildren);
505
506   const size_t numFilters( mFilters.Size() );
507   for( size_t i = 0; i < numFilters; ++i )
508   {
509     mFilters[i]->Disable();
510   }
511 }
512
513 void EffectsView::RefreshRenderTasks()
514 {
515   RenderTaskList taskList = Stage::GetCurrent().GetRenderTaskList();
516
517   if( mRenderTaskForChildren )
518   {
519     mRenderTaskForChildren.SetRefreshRate( mRefreshOnDemand ? RenderTask::REFRESH_ONCE : RenderTask::REFRESH_ALWAYS );
520   }
521
522   const size_t numFilters( mFilters.Size() );
523   for( size_t i = 0; i < numFilters; ++i )
524   {
525     mFilters[i]->Refresh();
526   }
527 }
528
529 void EffectsView::RemoveFilters()
530 {
531   const size_t numFilters( mFilters.Size() );
532   for( size_t i = 0; i < numFilters; ++i )
533   {
534     delete mFilters[i];
535   }
536   mFilters.Release();
537 }
538
539 void EffectsView::SetProperty( BaseObject* object, Property::Index index, const Property::Value& value )
540 {
541   Toolkit::EffectsView effectsView = Toolkit::EffectsView::DownCast( Dali::BaseHandle( object ) );
542
543   if ( effectsView )
544   {
545     switch ( index )
546     {
547       case Toolkit::EffectsView::Property::EFFECT_SIZE:
548       {
549         int effectSize;
550         if( value.Get( effectSize ) )
551         {
552           GetImpl( effectsView ).SetEffectSize( effectSize );
553         }
554         break;
555       }
556       default:
557       {
558         break;
559       }
560     }
561   }
562 }
563
564 Property::Value EffectsView::GetProperty( BaseObject* object, Property::Index propertyIndex )
565 {
566   Property::Value value;
567
568   Toolkit::EffectsView imageview = Toolkit::EffectsView::DownCast( Dali::BaseHandle( object ) );
569
570   if ( imageview )
571   {
572     EffectsView& impl = GetImpl( imageview );
573     switch ( propertyIndex )
574     {
575       case Toolkit::EffectsView::Property::EFFECT_SIZE:
576       {
577          value = impl.GetEffectSize();
578         break;
579       }
580       default:
581       {
582         break;
583       }
584     }
585   }
586
587   return value;
588 }
589
590 } // namespace Internal
591
592 } // namespace Toolkit
593
594 } // namespace Dali