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