Split dali-toolkit into Base & Optional
[platform/core/uifw/dali-toolkit.git] / optional / dali-toolkit / internal / controls / super-blur-view / super-blur-view-impl.cpp
1 //
2 // Copyright (c) 2014 Samsung Electronics Co., Ltd.
3 //
4 // Licensed under the Flora License, Version 1.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://floralicense.org/license/
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 //EXTERNAL INCLUDES
18 #include <cmath>
19 #include <integration-api/debug.h>
20
21 // CLASS HEADER
22 #include "super-blur-view-impl.h"
23
24 namespace //unnamed namespace
25 {
26
27 using namespace Dali;
28
29 //Todo: make these properties instead of constants
30 const unsigned int GAUSSIAN_BLUR_DEFAULT_NUM_SAMPLES = 11;
31 const unsigned int GAUSSIAN_BLUR_NUM_SAMPLES_INCREMENTATION = 10;
32 const float GAUSSIAN_BLUR_BELL_CURVE_WIDTH = 4.5f;
33 const float GAUSSIAN_BLUR_BELL_CURVE_WIDTH_INCREMENTATION = 5.f;
34 const Pixel::Format GAUSSIAN_BLUR_RENDER_TARGET_PIXEL_FORMAT = Pixel::RGB888;
35 const float GAUSSIAN_BLUR_DOWNSAMPLE_WIDTH_SCALE = 0.5f;
36 const float GAUSSIAN_BLUR_DOWNSAMPLE_HEIGHT_SCALE = 0.5f;
37
38 /**
39  * The constraint is used to blend the group of blurred images continuously with a unified blur strength property value which ranges from zero to one.
40  */
41 struct ActorOpacityConstraint
42 {
43   ActorOpacityConstraint(int totalImageNum, int currentImageIdx)
44   {
45     float rangeLength = 1.f / static_cast<float>( totalImageNum );
46     float index = static_cast<float>( currentImageIdx );
47     mRange = Vector2( index*rangeLength, (index+1.f)*rangeLength );
48   }
49
50   float operator()( float current, const PropertyInput& blurProperty )
51   {
52     float blurStrength = blurProperty.GetFloat();
53     if(blurStrength <= mRange.x)
54     {
55       return 1.f;
56     }
57     else if(blurStrength > mRange.y)
58     {
59       return 0.f;
60     }
61     else
62     {
63       return (mRange.y - blurStrength)/(mRange.y-mRange.x);
64     }
65   }
66
67   Vector2 mRange;
68 };
69
70 } // namespace
71
72 namespace Dali
73 {
74
75 namespace Toolkit
76 {
77
78 const Property::Index SuperBlurView::PROPERTY_IMAGE( Internal::SuperBlurView::SUPER_BLUR_VIEW_PROPERTY_START_INDEX );
79
80 namespace Internal
81 {
82
83 namespace
84 {
85 const unsigned int DEFAULT_BLUR_LEVEL(5u); ///< The default blur level when creating SuperBlurView from the type registry
86
87 BaseHandle Create()
88 {
89   return Toolkit::SuperBlurView::New( DEFAULT_BLUR_LEVEL );
90 }
91
92 // Type registration
93 TypeRegistration typeRegistration( typeid(Toolkit::SuperBlurView), typeid(Toolkit::Control), Create );
94
95 PropertyRegistration property1( typeRegistration, "image", Toolkit::SuperBlurView::PROPERTY_IMAGE,   Property::MAP, &SuperBlurView::SetProperty, &SuperBlurView::GetProperty );
96
97 } // unnamed namespace
98
99 SuperBlurView::SuperBlurView( unsigned int blurLevels )
100 : ControlImpl( false ),
101   mBlurLevels( blurLevels ),
102   mBlurStrengthPropertyIndex(Property::INVALID_INDEX),
103   mResourcesCleared( true ),
104   mTargetSize( Vector2::ZERO )
105 {
106   DALI_ASSERT_ALWAYS( mBlurLevels > 0 && " Minimal blur level is one, otherwise no blur is needed" );
107   mGaussianBlurView.resize( blurLevels );
108   mBlurredImage.resize( blurLevels );
109   mImageActors.resize( blurLevels + 1 );
110 }
111
112 SuperBlurView::~SuperBlurView()
113 {
114 }
115
116 Toolkit::SuperBlurView SuperBlurView::New( unsigned int blurLevels )
117 {
118   //Create the implementation
119   IntrusivePtr<SuperBlurView> superBlurView( new SuperBlurView( blurLevels ) );
120
121   //Pass ownership to CustomActor via derived handle
122   Toolkit::SuperBlurView handle( *superBlurView );
123
124   // Second-phase init of the implementation
125   // This can only be done after the CustomActor connection has been made...
126   superBlurView->Initialize();
127
128   return handle;
129 }
130
131 void SuperBlurView::OnInitialize()
132 {
133   mBlurStrengthPropertyIndex = Self().RegisterProperty( "blur-strength",0.f );
134
135   DALI_ASSERT_ALWAYS( mImageActors.size() == mBlurLevels+1 && "must synchronize the ImageActor group if blur levels got changed " );
136   for(unsigned int i=0; i<=mBlurLevels;i++)
137   {
138     mImageActors[i] = ImageActor::New(  );
139     mImageActors[i].SetParentOrigin( ParentOrigin::CENTER );
140     mImageActors[i].SetZ(-static_cast<float>(i)*0.01f);
141     mImageActors[i].SetColorMode( USE_OWN_MULTIPLY_PARENT_ALPHA );
142     Self().Add( mImageActors[i] );
143   }
144
145   for(unsigned int i=0; i < mBlurLevels; i++)
146   {
147     mImageActors[i].ApplyConstraint( Constraint::New<float>( Actor::COLOR_ALPHA, ParentSource( mBlurStrengthPropertyIndex ), ActorOpacityConstraint(mBlurLevels, i) ) );
148   }
149
150   Self().SetSize(Stage::GetCurrent().GetSize());
151 }
152
153 void SuperBlurView::SetImage(Image inputImage)
154 {
155   DALI_ASSERT_ALWAYS( mImageActors.size() == mBlurLevels+1 && "must synchronize the ImageActor group if blur levels got changed " );
156   DALI_ASSERT_ALWAYS( mBlurredImage.size() == mBlurLevels && "must synchronize the blurred image group if blur levels got changed " );
157
158   ClearBlurResource();
159
160   mImageActors[0].SetImage( inputImage );
161
162   for(unsigned int i=1; i<=mBlurLevels;i++)
163   {
164     mImageActors[i].SetImage( mBlurredImage[i-1] );
165   }
166
167   BlurImage( 0,  inputImage);
168   for(unsigned int i=1; i<mBlurLevels;i++)
169   {
170     BlurImage( i,  mBlurredImage[i-1]);
171   }
172
173   mResourcesCleared = false;
174 }
175
176 Property::Index SuperBlurView::GetBlurStrengthPropertyIndex() const
177 {
178   return mBlurStrengthPropertyIndex;
179 }
180
181 void SuperBlurView::SetBlurStrength( float blurStrength )
182 {
183   Self().SetProperty(mBlurStrengthPropertyIndex, blurStrength);
184 }
185
186 float SuperBlurView::GetCurrentBlurStrength() const
187 {
188   float blurStrength;
189   (Self().GetProperty( mBlurStrengthPropertyIndex )).Get(blurStrength);
190
191   return blurStrength;
192 }
193
194 Toolkit::SuperBlurView::SuperBlurViewSignal& SuperBlurView::BlurFinishedSignal()
195 {
196   return mBlurFinishedSignal;
197 }
198
199 Image SuperBlurView::GetBlurredImage( unsigned int level )
200 {
201   DALI_ASSERT_ALWAYS( level>0 && level<=mBlurLevels );
202   return mBlurredImage[level-1];
203 }
204
205 void SuperBlurView::BlurImage( unsigned int idx, Image image )
206 {
207   DALI_ASSERT_ALWAYS( mGaussianBlurView.size()>idx );
208   mGaussianBlurView[idx] = Toolkit::GaussianBlurView::New( GAUSSIAN_BLUR_DEFAULT_NUM_SAMPLES+GAUSSIAN_BLUR_NUM_SAMPLES_INCREMENTATION*idx,
209                                                            GAUSSIAN_BLUR_BELL_CURVE_WIDTH + GAUSSIAN_BLUR_BELL_CURVE_WIDTH_INCREMENTATION*static_cast<float>(idx),
210                                                            GAUSSIAN_BLUR_RENDER_TARGET_PIXEL_FORMAT,
211                                                            GAUSSIAN_BLUR_DOWNSAMPLE_WIDTH_SCALE, GAUSSIAN_BLUR_DOWNSAMPLE_HEIGHT_SCALE, true );
212   mGaussianBlurView[idx].SetParentOrigin(ParentOrigin::CENTER);
213   mGaussianBlurView[idx].SetSize(mTargetSize);
214   mGaussianBlurView[idx].SetUserImageAndOutputRenderTarget( image, mBlurredImage[idx] );
215   if( idx == mBlurLevels-1 )
216   {
217     mGaussianBlurView[idx].FinishedSignal().Connect( this, &SuperBlurView::OnBlurViewFinished );
218   }
219   Stage::GetCurrent().Add( mGaussianBlurView[idx] );
220   mGaussianBlurView[idx].ActivateOnce();
221 }
222
223 void SuperBlurView::OnBlurViewFinished( Toolkit::GaussianBlurView blurView )
224 {
225   ClearBlurResource();
226   Toolkit::SuperBlurView handle( GetOwner() );
227   mBlurFinishedSignal.Emit( handle );
228 }
229
230 void SuperBlurView::ClearBlurResource()
231 {
232   if( !mResourcesCleared )
233   {
234     DALI_ASSERT_ALWAYS( mGaussianBlurView.size() == mBlurLevels && "must synchronize the GaussianBlurView group if blur levels got changed " );
235     for(unsigned int i=0; i<mBlurLevels;i++)
236     {
237       Stage::GetCurrent().Remove( mGaussianBlurView[i] );
238       mGaussianBlurView[i].Deactivate();
239       mGaussianBlurView[i].Reset();
240     }
241     mResourcesCleared = true;
242   }
243 }
244
245 void SuperBlurView::OnRelaidOut( Vector2 size, ActorSizeContainer& container )
246 {
247   unsigned int numChildren = Self().GetChildCount();
248
249   for( unsigned int i=0; i<numChildren; ++i )
250   {
251     Self().GetChildAt(i).SetSize(size);
252   }
253 }
254
255 void SuperBlurView::OnControlSizeSet( const Vector3& targetSize )
256 {
257   if( mTargetSize != Vector2(targetSize) )
258   {
259     mTargetSize = Vector2(targetSize);
260
261     for(unsigned int i=0; i<mBlurLevels;i++)
262     {
263       float exponent = static_cast<float>(i+1);
264       mBlurredImage[i] = FrameBufferImage::New( mTargetSize.width/std::pow(2.f,exponent) , mTargetSize.height/std::pow(2.f,exponent),
265                                                 GAUSSIAN_BLUR_RENDER_TARGET_PIXEL_FORMAT, Dali::Image::Never );
266     }
267   }
268 }
269
270 void SuperBlurView::SetProperty( BaseObject* object, Property::Index propertyIndex, const Property::Value& value )
271 {
272   Toolkit::SuperBlurView superBlurView = Toolkit::SuperBlurView::DownCast( Dali::BaseHandle( object ) );
273
274   if ( superBlurView )
275   {
276     SuperBlurView& superBlurViewImpl( GetImpl( superBlurView ) );
277
278     switch ( propertyIndex )
279     {
280       case Toolkit::SuperBlurView::PROPERTY_IMAGE:
281       {
282         Dali::Image image = Scripting::NewImage( value );
283         if ( image )
284         {
285           superBlurViewImpl.SetImage( image );
286         }
287         else
288         {
289           DALI_LOG_ERROR( "Cannot create image from property value\n" );
290         }
291         break;
292       }
293     }
294   }
295 }
296
297 Property::Value SuperBlurView::GetProperty( BaseObject* object, Property::Index propertyIndex )
298 {
299   Property::Value value;
300
301   Toolkit::SuperBlurView pushButton = Toolkit::SuperBlurView::DownCast( Dali::BaseHandle( object ) );
302
303   if ( pushButton )
304   {
305     SuperBlurView& superBlurViewImpl( GetImpl( pushButton ) );
306
307     switch ( propertyIndex )
308     {
309       case Toolkit::SuperBlurView::PROPERTY_IMAGE:
310       {
311         Property::Map map;
312         if ( !superBlurViewImpl.mImageActors.empty() && superBlurViewImpl.mImageActors[0] )
313         {
314           Scripting::CreatePropertyMap( superBlurViewImpl.mImageActors[0], map );
315         }
316         value = Property::Value( map );
317         break;
318       }
319     }
320   }
321
322   return value;
323 }
324
325 } // namespace Internal
326
327 } // namespace Toolkit
328
329 } // namespace Dali