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