Merge "Size negotiation patch 2: Re-enable size negotiation on builder actors." into...
[platform/core/uifw/dali-toolkit.git] / 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 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 "super-blur-view-impl.h"
20
21 // EXTERNAL INCLUDES
22 #include <cmath>
23 #include <dali/public-api/animation/constraint.h>
24 #include <dali/public-api/common/stage.h>
25 #include <dali/public-api/object/type-registry.h>
26 #include <dali/public-api/object/type-registry-helper.h>
27 #include <dali/public-api/scripting/scripting.h>
28 #include <dali/integration-api/debug.h>
29
30 namespace //Unnamed namespace
31 {
32
33 using namespace Dali;
34
35 //Todo: make these properties instead of constants
36 const unsigned int GAUSSIAN_BLUR_DEFAULT_NUM_SAMPLES = 11;
37 const unsigned int GAUSSIAN_BLUR_NUM_SAMPLES_INCREMENTATION = 10;
38 const float GAUSSIAN_BLUR_BELL_CURVE_WIDTH = 4.5f;
39 const float GAUSSIAN_BLUR_BELL_CURVE_WIDTH_INCREMENTATION = 5.f;
40 const Pixel::Format GAUSSIAN_BLUR_RENDER_TARGET_PIXEL_FORMAT = Pixel::RGB888;
41 const float GAUSSIAN_BLUR_DOWNSAMPLE_WIDTH_SCALE = 0.5f;
42 const float GAUSSIAN_BLUR_DOWNSAMPLE_HEIGHT_SCALE = 0.5f;
43
44 /**
45  * 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.
46  */
47 struct ActorOpacityConstraint
48 {
49   ActorOpacityConstraint(int totalImageNum, int currentImageIdx)
50   {
51     float rangeLength = 1.f / static_cast<float>( totalImageNum );
52     float index = static_cast<float>( currentImageIdx );
53     mRange = Vector2( index*rangeLength, (index+1.f)*rangeLength );
54   }
55
56   void operator()( float& current, const PropertyInputContainer& inputs )
57   {
58     float blurStrength = inputs[0]->GetFloat();
59     if(blurStrength <= mRange.x)
60     {
61       current = 1.f;
62     }
63     else if(blurStrength > mRange.y)
64     {
65       current = 0.f;
66     }
67     else
68     {
69       current = ( mRange.y - blurStrength) / ( mRange.y - mRange.x );
70     }
71   }
72
73   Vector2 mRange;
74 };
75
76 } // namespace
77
78 namespace Dali
79 {
80
81 namespace Toolkit
82 {
83
84 namespace Internal
85 {
86
87 namespace
88 {
89
90 const unsigned int DEFAULT_BLUR_LEVEL(5u); ///< The default blur level when creating SuperBlurView from the type registry
91
92 BaseHandle Create()
93 {
94   return Toolkit::SuperBlurView::New( DEFAULT_BLUR_LEVEL );
95 }
96
97 // Setup properties, signals and actions using the type-registry.
98 DALI_TYPE_REGISTRATION_BEGIN( Toolkit::SuperBlurView, Toolkit::Control, Create )
99
100 DALI_PROPERTY_REGISTRATION( SuperBlurView, "image", MAP, IMAGE )
101
102 DALI_TYPE_REGISTRATION_END()
103
104 } // unnamed namespace
105
106 SuperBlurView::SuperBlurView( unsigned int blurLevels )
107 : Control( CONTROL_BEHAVIOUR_NONE ),
108   mBlurLevels( blurLevels ),
109   mBlurStrengthPropertyIndex(Property::INVALID_INDEX),
110   mResourcesCleared( true ),
111   mTargetSize( Vector2::ZERO )
112 {
113   DALI_ASSERT_ALWAYS( mBlurLevels > 0 && " Minimal blur level is one, otherwise no blur is needed" );
114   mGaussianBlurView.assign( blurLevels, NULL );
115   mBlurredImage.assign( blurLevels, FrameBufferImage() );
116   mImageActors.assign( blurLevels + 1, ImageActor() );
117 }
118
119 SuperBlurView::~SuperBlurView()
120 {
121 }
122
123 Toolkit::SuperBlurView SuperBlurView::New( unsigned int blurLevels )
124 {
125   //Create the implementation
126   IntrusivePtr<SuperBlurView> superBlurView( new SuperBlurView( blurLevels ) );
127
128   //Pass ownership to CustomActor via derived handle
129   Toolkit::SuperBlurView handle( *superBlurView );
130
131   // Second-phase init of the implementation
132   // This can only be done after the CustomActor connection has been made...
133   superBlurView->Initialize();
134
135   return handle;
136 }
137
138 void SuperBlurView::OnInitialize()
139 {
140   mBlurStrengthPropertyIndex = Self().RegisterProperty( "blur-strength",0.f );
141
142   DALI_ASSERT_ALWAYS( mImageActors.size() == mBlurLevels+1 && "must synchronize the ImageActor group if blur levels got changed " );
143   for(unsigned int i=0; i<=mBlurLevels;i++)
144   {
145     mImageActors[i] = ImageActor::New(  );
146     mImageActors[i].SetResizePolicy( FILL_TO_PARENT, ALL_DIMENSIONS );
147     mImageActors[i].SetParentOrigin( ParentOrigin::CENTER );
148     mImageActors[i].SetZ(-static_cast<float>(i)*0.01f);
149     mImageActors[i].SetColorMode( USE_OWN_MULTIPLY_PARENT_ALPHA );
150     Self().Add( mImageActors[i] );
151   }
152
153   for(unsigned int i=0; i < mBlurLevels; i++)
154   {
155     Constraint constraint = Constraint::New<float>( mImageActors[i], Actor::Property::COLOR_ALPHA, ActorOpacityConstraint(mBlurLevels, i) );
156     constraint.AddSource( ParentSource( mBlurStrengthPropertyIndex ) );
157     constraint.Apply();
158   }
159
160   Self().SetSize(Stage::GetCurrent().GetSize());
161 }
162
163 void SuperBlurView::SetImage(Image inputImage)
164 {
165   DALI_ASSERT_ALWAYS( mImageActors.size() == mBlurLevels+1 && "must synchronize the ImageActor group if blur levels got changed " );
166   DALI_ASSERT_ALWAYS( mBlurredImage.size() == mBlurLevels && "must synchronize the blurred image group if blur levels got changed " );
167
168   ClearBlurResource();
169
170   mImageActors[0].SetImage( inputImage );
171
172   for(unsigned int i=1; i<=mBlurLevels;i++)
173   {
174     mImageActors[i].SetImage( mBlurredImage[i-1] );
175   }
176
177   BlurImage( 0,  inputImage);
178   for(unsigned int i=1; i<mBlurLevels;i++)
179   {
180     BlurImage( i,  mBlurredImage[i-1]);
181   }
182
183   mResourcesCleared = false;
184 }
185
186 Property::Index SuperBlurView::GetBlurStrengthPropertyIndex() const
187 {
188   return mBlurStrengthPropertyIndex;
189 }
190
191 void SuperBlurView::SetBlurStrength( float blurStrength )
192 {
193   Self().SetProperty(mBlurStrengthPropertyIndex, blurStrength);
194 }
195
196 float SuperBlurView::GetCurrentBlurStrength() const
197 {
198   float blurStrength;
199   (Self().GetProperty( mBlurStrengthPropertyIndex )).Get(blurStrength);
200
201   return blurStrength;
202 }
203
204 Toolkit::SuperBlurView::SuperBlurViewSignal& SuperBlurView::BlurFinishedSignal()
205 {
206   return mBlurFinishedSignal;
207 }
208
209 Image SuperBlurView::GetBlurredImage( unsigned int level )
210 {
211   DALI_ASSERT_ALWAYS( level>0 && level<=mBlurLevels );
212   return mBlurredImage[level-1];
213 }
214
215 void SuperBlurView::BlurImage( unsigned int idx, Image image )
216 {
217   DALI_ASSERT_ALWAYS( mGaussianBlurView.size()>idx );
218   mGaussianBlurView[idx] = Toolkit::GaussianBlurView::New( GAUSSIAN_BLUR_DEFAULT_NUM_SAMPLES+GAUSSIAN_BLUR_NUM_SAMPLES_INCREMENTATION*idx,
219                                                            GAUSSIAN_BLUR_BELL_CURVE_WIDTH + GAUSSIAN_BLUR_BELL_CURVE_WIDTH_INCREMENTATION*static_cast<float>(idx),
220                                                            GAUSSIAN_BLUR_RENDER_TARGET_PIXEL_FORMAT,
221                                                            GAUSSIAN_BLUR_DOWNSAMPLE_WIDTH_SCALE, GAUSSIAN_BLUR_DOWNSAMPLE_HEIGHT_SCALE, true );
222   mGaussianBlurView[idx].SetParentOrigin(ParentOrigin::CENTER);
223   mGaussianBlurView[idx].SetSize(mTargetSize);
224   mGaussianBlurView[idx].SetUserImageAndOutputRenderTarget( image, mBlurredImage[idx] );
225   if( idx == mBlurLevels-1 )
226   {
227     mGaussianBlurView[idx].FinishedSignal().Connect( this, &SuperBlurView::OnBlurViewFinished );
228   }
229   Stage::GetCurrent().Add( mGaussianBlurView[idx] );
230   mGaussianBlurView[idx].ActivateOnce();
231 }
232
233 void SuperBlurView::OnBlurViewFinished( Toolkit::GaussianBlurView blurView )
234 {
235   ClearBlurResource();
236   Toolkit::SuperBlurView handle( GetOwner() );
237   mBlurFinishedSignal.Emit( handle );
238 }
239
240 void SuperBlurView::ClearBlurResource()
241 {
242   if( !mResourcesCleared )
243   {
244     DALI_ASSERT_ALWAYS( mGaussianBlurView.size() == mBlurLevels && "must synchronize the GaussianBlurView group if blur levels got changed " );
245     for(unsigned int i=0; i<mBlurLevels;i++)
246     {
247       Stage::GetCurrent().Remove( mGaussianBlurView[i] );
248       mGaussianBlurView[i].Deactivate();
249       mGaussianBlurView[i].Reset();
250     }
251     mResourcesCleared = true;
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     if( propertyIndex == Toolkit::SuperBlurView::Property::IMAGE )
279     {
280       Dali::Image image = Scripting::NewImage( value );
281       if ( image )
282       {
283         superBlurViewImpl.SetImage( image );
284       }
285       else
286       {
287         DALI_LOG_ERROR( "Cannot create image from property value\n" );
288       }
289     }
290   }
291 }
292
293 Property::Value SuperBlurView::GetProperty( BaseObject* object, Property::Index propertyIndex )
294 {
295   Property::Value value;
296
297   Toolkit::SuperBlurView pushButton = Toolkit::SuperBlurView::DownCast( Dali::BaseHandle( object ) );
298
299   if( pushButton )
300   {
301     SuperBlurView& superBlurViewImpl( GetImpl( pushButton ) );
302
303     if( propertyIndex == Toolkit::SuperBlurView::Property::IMAGE )
304     {
305       Property::Map map;
306       if( !superBlurViewImpl.mImageActors.empty() && superBlurViewImpl.mImageActors[0] )
307       {
308         Scripting::CreatePropertyMap( superBlurViewImpl.mImageActors[0], map );
309       }
310       value = Property::Value( map );
311     }
312   }
313
314   return value;
315 }
316
317 } // namespace Internal
318
319 } // namespace Toolkit
320
321 } // namespace Dali