8304e0efeeb9dad4e29906896df7e85a8c52b9ff
[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/active-constraint.h>
23 #include <dali/public-api/animation/constraint.h>
24 #include <dali/public-api/animation/constraints.h>
25 #include <dali/public-api/common/stage.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 "../../filters/blur-two-pass-filter.h"
32 #include "../../filters/emboss-filter.h"
33 #include "../../filters/spread-filter.h"
34
35 namespace Dali
36 {
37
38 namespace Toolkit
39 {
40
41 namespace Internal
42 {
43
44 namespace
45 {
46
47 Dali::BaseHandle Create()
48 {
49   return Toolkit::EffectsView::New();
50 }
51
52 DALI_TYPE_REGISTRATION_BEGIN( Toolkit::EffectsView, Toolkit::Control, Create )
53 DALI_TYPE_REGISTRATION_END()
54
55 const Pixel::Format EFFECTS_VIEW_DEFAULT_PIXEL_FORMAT = Pixel::RGBA8888;
56 const float         ARBITRARY_FIELD_OF_VIEW = Math::PI / 4.0f;
57 const Vector4       EFFECTS_VIEW_DEFAULT_BACKGROUND_COLOR( 1.0f, 1.0f, 1.0f, 0.0 );
58 const bool          EFFECTS_VIEW_REFRESH_ON_DEMAND(false);
59
60 // Custom properties
61 const char* const   EFFECT_SIZE_PROPERTY_NAME = "EffectSize";
62 const char* const   EFFECT_STRENGTH_PROPERTY_NAME = "EffectStrength";
63 const char* const   EFFECT_OFFSET_PROPERTY_NAME = "EffectOffset";
64 const char* const   EFFECT_COLOR_PROPERTY_NAME = "EffectColor";
65
66 const float         EFFECT_SIZE_DEFAULT( 1.0f );
67 const float         EFFECT_STRENGTH_DEFAULT( 0.5f );
68 const Vector3       EFFECT_OFFSET_DEFAULT( 0.0f, 0.0f, 0.0f );
69 const Vector4       EFFECT_COLOR_DEFAULT( Color::WHITE );
70
71 const char* const EFFECTS_VIEW_FRAGMENT_SOURCE =
72     "void main()\n"
73     "{\n"
74     "  gl_FragColor = uColor;\n"
75     "  gl_FragColor.a *= texture2D( sTexture, vTexCoord).a;\n"
76     "}\n";
77
78 const float BLUR_KERNEL0[] = { 12.0f/16.0f,
79                                2.0f/16.0f, 2.0f/16.0f };
80
81 const float BLUR_KERNEL1[] = { 8.0f/16.0f,
82                                4.0f/16.0f, 4.0f/16.0f };
83
84 const float BLUR_KERNEL2[] = { 6.0f/16.0f,
85                                2.5f/16.0f, 2.5f/16.0f,
86                                1.5f/16.0f, 1.5f/16.0f,
87                                1.0f/16.0f, 1.0f/16.0f };
88
89 const float BLUR_KERNEL3[] = { 4.0f/16.0f,
90                                3.0f/16.0f, 2.0f/16.0f,
91                                2.0f/16.0f, 2.0f/16.0f,
92                                1.0f/16.0f, 1.0f/16.0f };
93
94 const float BLUR_KERNEL4[] = { 3.0f/16.0f,
95                                2.5f/16.0f,  2.5f/16.0f,
96                                1.75f/16.0f, 1.75f/16.0f,
97                                1.25f/16.0f, 1.25f/16.0f,
98                                1.0f/16.0f,  1.0f/16.0f };
99
100 } // namespace
101
102 Toolkit::EffectsView EffectsView::New()
103 {
104   EffectsView* effectsView = new EffectsView;
105
106   Toolkit::EffectsView handle = Toolkit::EffectsView( *effectsView );
107
108   // Second-phase init of the implementation
109   // This can only be done after the CustomActor connection has been made...
110   effectsView->Initialize();
111
112   return handle;
113 }
114
115 EffectsView::EffectsView()
116 : Control( CONTROL_BEHAVIOUR_NONE ),
117   mEffectType( Toolkit::EffectsView::INVALID_TYPE ),
118   mPixelFormat( EFFECTS_VIEW_DEFAULT_PIXEL_FORMAT ),
119   mSpread(0.0f),
120   mBackgroundColor( EFFECTS_VIEW_DEFAULT_BACKGROUND_COLOR ),
121   mTargetSize( Vector2::ZERO ),
122   mLastSize( Vector2::ZERO ),
123   mRefreshOnDemand(EFFECTS_VIEW_REFRESH_ON_DEMAND),
124   mEffectSizePropertyIndex(Property::INVALID_INDEX),
125   mEffectStrengthPropertyIndex(Property::INVALID_INDEX),
126   mEffectOffsetPropertyIndex(Property::INVALID_INDEX),
127   mEffectColorPropertyIndex(Property::INVALID_INDEX)
128 {
129 }
130
131 EffectsView::~EffectsView()
132 {
133   RemoveFilters();
134 }
135
136 void EffectsView::SetType( Toolkit::EffectsView::EffectType type )
137 {
138   if( mEffectType != type )
139   {
140     mEffectType = type;
141
142     RemoveFilters();
143
144     switch( mEffectType )
145     {
146       case Toolkit::EffectsView::DROP_SHADOW:
147       {
148         mFilters.push_back( new SpreadFilter );
149         mFilters.push_back( new BlurTwoPassFilter );
150         break;
151       }
152       case Toolkit::EffectsView::EMBOSS:
153       {
154         mFilters.push_back( new SpreadFilter );
155         mFilters.push_back( new EmbossFilter );
156         mFilters.push_back( new BlurTwoPassFilter );
157         mActorPostFilter.RemoveShaderEffect();
158         break;
159       }
160       default:
161       {
162         break;
163       }
164     }
165   }
166 }
167
168 Toolkit::EffectsView::EffectType EffectsView::GetType() const
169 {
170   return mEffectType;
171 }
172
173 void EffectsView::Enable()
174 {
175   // make sure resources are allocated and start the render tasks processing
176   AllocateResources();
177   CreateRenderTasks();
178 }
179
180 void EffectsView::Disable()
181 {
182   // stop render tasks processing
183   // Note: render target resources are automatically freed since we set the Image::Unused flag
184   RemoveRenderTasks();
185 }
186
187 void EffectsView::Refresh()
188 {
189   RefreshRenderTasks();
190 }
191
192 void EffectsView::SetRefreshOnDemand( bool onDemand )
193 {
194   mRefreshOnDemand = onDemand;
195
196   RefreshRenderTasks();
197 }
198
199 void EffectsView::SetPixelFormat( Pixel::Format pixelFormat )
200 {
201   mPixelFormat = pixelFormat;
202 }
203
204 void EffectsView::SetOutputImage( FrameBufferImage image )
205 {
206   CustomActor self = Self();
207
208   if( mImageForResult != image )
209   {
210     if( !image )
211     {
212       if( mImageForResult )
213       {
214         self.Remove( mActorForResult );
215         mActorForResult.Reset();
216
217         self.Add( mActorPostFilter );
218         self.Add( mActorForChildren );
219       }
220     }
221     else
222     {
223       if( mImageForResult )
224       {
225         self.Remove( mActorForResult );
226       }
227       mActorForResult = Actor::New();
228       mActorForResult.SetParentOrigin( ParentOrigin::CENTER );
229       mActorForResult.SetSize( mTargetSize );
230       mActorForResult.ScaleBy( Vector3(1.0f, -1.0f, 1.0f) );
231
232       Self().Add( mActorForResult );
233       mActorForResult.Add( mActorPostFilter );
234       mActorForResult.Add( mActorForChildren );
235     }
236     mImageForResult = image;
237   }
238 }
239
240 FrameBufferImage EffectsView::GetOutputImage()
241 {
242   return mImageForResult;
243 }
244
245 Property::Index EffectsView::GetEffectSizePropertyIndex() const
246 {
247   return mEffectSizePropertyIndex;
248 }
249
250 Property::Index EffectsView::GetEffectStrengthPropertyIndex() const
251 {
252   return mEffectStrengthPropertyIndex;
253 }
254
255 Property::Index EffectsView::GetEffectOffsetPropertyIndex() const
256 {
257   return mEffectOffsetPropertyIndex;
258 }
259
260 Property::Index EffectsView::GetEffectColorPropertyIndex() const
261 {
262   return mEffectColorPropertyIndex;
263 }
264
265 void EffectsView::SetupProperties()
266 {
267   CustomActor self = Self();
268
269   // Register a property that the user can control the drop shadow offset
270   mEffectSizePropertyIndex     = self.RegisterProperty(EFFECT_SIZE_PROPERTY_NAME, EFFECT_SIZE_DEFAULT, Property::READ_WRITE);
271   mEffectStrengthPropertyIndex = self.RegisterProperty(EFFECT_STRENGTH_PROPERTY_NAME, EFFECT_STRENGTH_DEFAULT, Property::READ_WRITE);
272   mEffectOffsetPropertyIndex   = self.RegisterProperty(EFFECT_OFFSET_PROPERTY_NAME, EFFECT_OFFSET_DEFAULT);
273   mEffectColorPropertyIndex    = self.RegisterProperty(EFFECT_COLOR_PROPERTY_NAME, EFFECT_COLOR_DEFAULT);
274   mActorPostFilter.ApplyConstraint( Constraint::New<Vector3>( Actor::Property::POSITION, Source( self, mEffectOffsetPropertyIndex ), EqualToConstraint() ) );
275   mActorPostFilter.ApplyConstraint( Constraint::New<Vector4>( Actor::Property::COLOR, Source( self, mEffectColorPropertyIndex ), EqualToConstraint() ) );
276 }
277
278 void EffectsView::SetBackgroundColor( const Vector4& color )
279 {
280   mBackgroundColor = color;
281 }
282
283 Vector4 EffectsView::GetBackgroundColor() const
284 {
285   return mBackgroundColor;
286 }
287
288 // From Control
289 void EffectsView::OnInitialize()
290 {
291   //////////////////////////////////////////////////////
292   // Create cameras
293   mCameraForChildren = CameraActor::New();
294   mCameraForChildren.SetParentOrigin(ParentOrigin::CENTER);
295
296   mActorForChildren = ImageActor::New();
297   mActorForChildren.SetPositionInheritanceMode( Dali::USE_PARENT_POSITION );
298   mActorForChildren.ScaleBy( Vector3(1.0f, -1.0f, 1.0f) );
299
300   mActorPostFilter = ImageActor::New();
301   mActorPostFilter.SetParentOrigin( ParentOrigin::CENTER );
302   mActorPostFilter.ScaleBy( Vector3(1.0f, -1.0f, 1.0f) );
303   mActorPostFilter.SetShaderEffect( ShaderEffect::New( "", EFFECTS_VIEW_FRAGMENT_SOURCE ) );
304
305   // Connect to actor tree
306   Self().Add( mActorPostFilter );
307   Self().Add( mActorForChildren );
308   Self().Add( mCameraForChildren );
309
310   SetupProperties();
311 }
312
313 void EffectsView::OnControlSizeSet(const Vector3& targetSize)
314 {
315   mTargetSize = Vector2(targetSize);
316
317   // if we are already on stage, need to update render target sizes now to reflect the new size of this actor
318   if(Self().OnStage())
319   {
320     AllocateResources();
321   }
322
323   if( mActorForResult )
324   {
325     mActorForResult.SetSize( targetSize );
326   }
327   if( mActorForChildren )
328   {
329     mActorForChildren.SetSize( targetSize );
330   }
331   if( mActorPostFilter )
332   {
333     mActorPostFilter.SetSize( targetSize );
334   }
335
336   // Children render camera must move when EffectsView object is resized.
337   // This is since we cannot change render target size - so we need to remap the child actors' rendering
338   // accordingly so they still exactly fill the render target.
339   // Note that this means the effective resolution of the child render changes as the EffectsView object
340   // changes size, this is the trade off for not being able to modify render target size
341   // Change camera z position based on EffectsView actor height
342   if( mCameraForChildren )
343   {
344     const float cameraPosScale( 0.5f / tanf(ARBITRARY_FIELD_OF_VIEW * 0.5f) );
345     mCameraForChildren.SetZ( targetSize.height * cameraPosScale );
346   }
347
348   const size_t numFilters( mFilters.size() );
349   for( size_t i = 0; i < numFilters; ++i )
350   {
351     mFilters[i]->SetSize( mTargetSize );
352   }
353
354 }
355
356 void EffectsView::OnStageDisconnection()
357 {
358   const size_t numFilters( mFilters.size() );
359   for( size_t i = 0; i < numFilters; ++i )
360   {
361     mFilters[i]->Disable();
362   }
363 }
364
365 void EffectsView::SetupFilters()
366 {
367   int effectSize = static_cast< int >( Self().GetProperty( mEffectSizePropertyIndex ).Get<float>() );
368   switch( mEffectType )
369   {
370     case Toolkit::EffectsView::DROP_SHADOW:
371     {
372       SpreadFilter* spreadFilter = static_cast< SpreadFilter* >( mFilters[0] );
373       spreadFilter->SetInputImage( mImageForChildren );
374       spreadFilter->SetOutputImage( mImagePostFilter );
375       spreadFilter->SetRootActor( Self() );
376       spreadFilter->SetBackgroundColor( mBackgroundColor );
377       spreadFilter->SetPixelFormat( mPixelFormat );
378       spreadFilter->SetSize( mTargetSize );
379       spreadFilter->SetSpread( effectSize );
380
381       BlurTwoPassFilter* blurFilter = static_cast< BlurTwoPassFilter* >( mFilters[1] );
382       blurFilter->SetInputImage( mImagePostFilter );
383       blurFilter->SetOutputImage( mImagePostFilter );
384       blurFilter->SetRootActor( Self() );
385       blurFilter->SetBackgroundColor( mBackgroundColor );
386       blurFilter->SetPixelFormat( mPixelFormat );
387       blurFilter->SetSize( mTargetSize );
388
389       const float* kernel(NULL);
390       size_t kernelSize(0);
391       switch( effectSize )
392       {
393         case 4:  {  kernel = BLUR_KERNEL4; kernelSize = sizeof(BLUR_KERNEL4)/sizeof(BLUR_KERNEL4[0]); break; }
394         case 3:  {  kernel = BLUR_KERNEL3; kernelSize = sizeof(BLUR_KERNEL3)/sizeof(BLUR_KERNEL3[0]); break; }
395         case 2:  {  kernel = BLUR_KERNEL2; kernelSize = sizeof(BLUR_KERNEL2)/sizeof(BLUR_KERNEL2[0]); break; }
396         case 1:  {  kernel = BLUR_KERNEL1; kernelSize = sizeof(BLUR_KERNEL1)/sizeof(BLUR_KERNEL1[0]); break; }
397         case 0:
398         default: {  kernel = BLUR_KERNEL0; kernelSize = sizeof(BLUR_KERNEL0)/sizeof(BLUR_KERNEL0[0]); break; }
399       }
400       blurFilter->CreateKernel( kernel, kernelSize );
401       break;
402     }
403     case Toolkit::EffectsView::EMBOSS:
404     {
405       SpreadFilter* spreadFilter = static_cast< SpreadFilter* >( mFilters[0] );
406       spreadFilter->SetInputImage( mImageForChildren );
407       spreadFilter->SetOutputImage( mImagePostFilter );
408       spreadFilter->SetRootActor( Self() );
409       spreadFilter->SetBackgroundColor( mBackgroundColor );
410       spreadFilter->SetPixelFormat( Pixel::RGBA8888 );
411       spreadFilter->SetSize( mTargetSize );
412       spreadFilter->SetSpread( effectSize );
413
414       EmbossFilter* embossFilter = static_cast< EmbossFilter* >( mFilters[1] );
415       embossFilter->SetInputImage( mImagePostFilter );
416       embossFilter->SetOutputImage( mImagePostFilter );
417       embossFilter->SetRootActor( Self() );
418       embossFilter->SetBackgroundColor( mBackgroundColor );
419       embossFilter->SetPixelFormat( Pixel::RGBA8888 );
420       embossFilter->SetSize( mTargetSize );
421
422       BlurTwoPassFilter* blurFilter = static_cast< BlurTwoPassFilter* >( mFilters[2] );
423       blurFilter->SetInputImage( mImagePostFilter );
424       blurFilter->SetOutputImage( mImagePostFilter );
425       blurFilter->SetRootActor( Self() );
426       blurFilter->SetBackgroundColor( Vector4( 0.5f, 0.5f, 0.5f, 0.0 ) );
427       blurFilter->SetPixelFormat( Pixel::RGBA8888 );
428       blurFilter->SetSize( mTargetSize );
429       blurFilter->CreateKernel( BLUR_KERNEL0, sizeof(BLUR_KERNEL0)/sizeof(BLUR_KERNEL0[0]) );
430
431       break;
432     }
433     default:
434     {
435       break;
436     }
437   }
438 }
439 void EffectsView::AllocateResources()
440 {
441   if(mTargetSize != mLastSize)
442   {
443     mLastSize = mTargetSize;
444
445     SetupCameras();
446
447     mImageForChildren = FrameBufferImage::New( mTargetSize.width, mTargetSize.height, mPixelFormat, Dali::Image::UNUSED );
448     mActorForChildren.SetImage(mImageForChildren);
449
450     mImagePostFilter = FrameBufferImage::New( mTargetSize.width, mTargetSize.height, mPixelFormat, Dali::Image::UNUSED );
451     mActorPostFilter.SetImage(mImagePostFilter);
452
453     SetupFilters();
454   }
455 }
456
457 void EffectsView::SetupCameras()
458 {
459   const float cameraPosScale( 0.5f / tanf(ARBITRARY_FIELD_OF_VIEW * 0.5f) );
460
461   // Create and place a camera for the children render, corresponding to its render target size
462   mCameraForChildren.SetFieldOfView(ARBITRARY_FIELD_OF_VIEW);
463   // TODO: how do we pick a reasonable value for near clip? Needs to relate to normal camera the user renders with, but we don't have a handle on it
464   mCameraForChildren.SetNearClippingPlane(1.0f);
465   mCameraForChildren.SetAspectRatio(mTargetSize.width / mTargetSize.height);
466   mCameraForChildren.SetType(Dali::Camera::FREE_LOOK); // camera orientation based solely on actor
467   mCameraForChildren.SetPosition(0.0f, 0.0f, mTargetSize.height * cameraPosScale);
468   mCameraForChildren.SetRotation(Quaternion(M_PI, Vector3::YAXIS));
469   mCameraForChildren.SetZ( mTargetSize.height * cameraPosScale );
470 }
471
472 void EffectsView::CreateRenderTasks()
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( Self() );
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   // create render task to render result of the image filters to the final offscreen
495   if( mImageForResult )
496   {
497     mRenderTaskForResult = taskList.CreateTask();
498     mRenderTaskForResult.SetRefreshRate( mRefreshOnDemand ? RenderTask::REFRESH_ONCE : RenderTask::REFRESH_ALWAYS );
499     mRenderTaskForResult.SetSourceActor( mActorForResult );
500     mRenderTaskForResult.SetExclusive(true);
501     mRenderTaskForResult.SetInputEnabled( false );
502     mRenderTaskForResult.SetClearColor( mBackgroundColor );
503     mRenderTaskForResult.SetClearEnabled( true );
504     mRenderTaskForResult.SetTargetFrameBuffer( mImageForResult );
505     mRenderTaskForResult.SetCameraActor(mCameraForChildren); // use camera that covers render target exactly
506   }
507 }
508
509 void EffectsView::RemoveRenderTasks()
510 {
511   RenderTaskList taskList = Stage::GetCurrent().GetRenderTaskList();
512
513   taskList.RemoveTask(mRenderTaskForChildren);
514   taskList.RemoveTask(mRenderTaskForResult);
515
516   const size_t numFilters( mFilters.size() );
517   for( size_t i = 0; i < numFilters; ++i )
518   {
519     mFilters[i]->Disable();
520   }
521 }
522
523 void EffectsView::RefreshRenderTasks()
524 {
525   RenderTaskList taskList = Stage::GetCurrent().GetRenderTaskList();
526
527   if( mRenderTaskForChildren )
528   {
529     mRenderTaskForChildren.SetRefreshRate( mRefreshOnDemand ? RenderTask::REFRESH_ONCE : RenderTask::REFRESH_ALWAYS );
530   }
531
532   if( mRenderTaskForResult )
533   {
534     mRenderTaskForResult.SetRefreshRate( mRefreshOnDemand ? RenderTask::REFRESH_ONCE : RenderTask::REFRESH_ALWAYS );
535   }
536
537   const size_t numFilters( mFilters.size() );
538   for( size_t i = 0; i < numFilters; ++i )
539   {
540     mFilters[i]->Refresh();
541   }
542 }
543
544 void EffectsView::RemoveFilters()
545 {
546   const size_t numFilters( mFilters.size() );
547   for( size_t i = 0; i < numFilters; ++i )
548   {
549     delete mFilters[i];
550   }
551   mFilters.clear();
552 }
553
554 } // namespace Internal
555
556 } // namespace Toolkit
557
558 } // namespace Dali