fa9839251c81d951be4f7fe8a65d47936e7e4477
[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 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
20 // CLASS HEADER
21 #include "super-blur-view-impl.h"
22
23 namespace //unnamed namespace
24 {
25
26 using namespace Dali;
27
28 //Type registration
29 TypeRegistration mType( typeid(Toolkit::SuperBlurView), typeid(Toolkit::Control), NULL );
30
31 //Todo: make these properties instead of constants
32 const unsigned int GAUSSIAN_BLUR_DEFAULT_NUM_SAMPLES = 11;
33 const unsigned int GAUSSIAN_BLUR_NUM_SAMPLES_INCREMENTATION = 10;
34 const float GAUSSIAN_BLUR_BELL_CURVE_WIDTH = 4.5f;
35 const float GAUSSIAN_BLUR_BELL_CURVE_WIDTH_INCREMENTATION = 5.f;
36 const Pixel::Format GAUSSIAN_BLUR_RENDER_TARGET_PIXEL_FORMAT = Pixel::RGB888;
37 const float GAUSSIAN_BLUR_DOWNSAMPLE_WIDTH_SCALE = 0.5f;
38 const float GAUSSIAN_BLUR_DOWNSAMPLE_HEIGHT_SCALE = 0.5f;
39
40 /**
41  * 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.
42  */
43 struct ActorOpacityConstraint
44 {
45   ActorOpacityConstraint(int totalImageNum, int currentImageIdx)
46   {
47     float rangeLength = 1.f / static_cast<float>( totalImageNum );
48     float index = static_cast<float>( currentImageIdx );
49     mRange = Vector2( index*rangeLength, (index+1.f)*rangeLength );
50   }
51
52   float operator()( float current, const PropertyInput& blurProperty )
53   {
54     float blurStrength = blurProperty.GetFloat();
55     if(blurStrength <= mRange.x)
56     {
57       return 1.f;
58     }
59     else if(blurStrength > mRange.y)
60     {
61       return 0.f;
62     }
63     else
64     {
65       return (mRange.y - blurStrength)/(mRange.y-mRange.x);
66     }
67   }
68
69   Vector2 mRange;
70 };
71
72 } // namespace
73
74 namespace Dali
75 {
76
77 namespace Toolkit
78 {
79
80 namespace Internal
81 {
82
83 SuperBlurView::SuperBlurView( unsigned int blurLevels )
84 : ControlImpl( false ),
85   mBlurLevels( blurLevels ),
86   mBlurStrengthPropertyIndex(Property::INVALID_INDEX),
87   mResourcesCleared( true ),
88   mTargetSize( Vector2::ZERO )
89 {
90   DALI_ASSERT_ALWAYS( mBlurLevels > 0 && " Minimal blur level is one, otherwise no blur is needed" );
91   mGaussianBlurView.resize( blurLevels );
92   mBlurredImage.resize( blurLevels );
93   mImageActors.resize( blurLevels + 1 );
94 }
95
96 SuperBlurView::~SuperBlurView()
97 {
98 }
99
100 Toolkit::SuperBlurView SuperBlurView::New( unsigned int blurLevels )
101 {
102   //Create the implementation
103   IntrusivePtr<SuperBlurView> superBlurView( new SuperBlurView( blurLevels ) );
104
105   //Pass ownership to CustomActor via derived handle
106   Toolkit::SuperBlurView handle( *superBlurView );
107
108   // Second-phase init of the implementation
109   // This can only be done after the CustomActor connection has been made...
110   superBlurView->Initialize();
111
112   return handle;
113 }
114
115 void SuperBlurView::OnInitialize()
116 {
117   mBlurStrengthPropertyIndex = Self().RegisterProperty( "BLUR_STRENGTH",0.f );
118
119   DALI_ASSERT_ALWAYS( mImageActors.size() == mBlurLevels+1 && "must synchronize the ImageActor group if blur levels got changed " );
120   for(unsigned int i=0; i<=mBlurLevels;i++)
121   {
122     mImageActors[i] = ImageActor::New(  );
123     mImageActors[i].SetParentOrigin( ParentOrigin::CENTER );
124     mImageActors[i].SetZ(-static_cast<float>(i)*0.01f);
125     mImageActors[i].SetColorMode( USE_OWN_MULTIPLY_PARENT_ALPHA );
126     Self().Add( mImageActors[i] );
127   }
128
129   for(unsigned int i=0; i < mBlurLevels; i++)
130   {
131     mImageActors[i].ApplyConstraint( Constraint::New<float>( Actor::COLOR_ALPHA, ParentSource( mBlurStrengthPropertyIndex ), ActorOpacityConstraint(mBlurLevels, i) ) );
132   }
133
134   Self().SetSize(Stage::GetCurrent().GetSize());
135 }
136
137 void SuperBlurView::SetImage(Image inputImage)
138 {
139   DALI_ASSERT_ALWAYS( mImageActors.size() == mBlurLevels+1 && "must synchronize the ImageActor group if blur levels got changed " );
140   DALI_ASSERT_ALWAYS( mBlurredImage.size() == mBlurLevels && "must synchronize the blurred image group if blur levels got changed " );
141
142   ClearBlurResource();
143
144   mImageActors[0].SetImage( inputImage );
145
146   for(unsigned int i=1; i<=mBlurLevels;i++)
147   {
148     mImageActors[i].SetImage( mBlurredImage[i-1] );
149   }
150
151   BlurImage( 0,  inputImage);
152   for(unsigned int i=1; i<mBlurLevels;i++)
153   {
154     BlurImage( i,  mBlurredImage[i-1]);
155   }
156
157   mResourcesCleared = false;
158 }
159
160 Property::Index SuperBlurView::GetBlurStrengthPropertyIndex() const
161 {
162   return mBlurStrengthPropertyIndex;
163 }
164
165 void SuperBlurView::SetBlurStrength( float blurStrength )
166 {
167   Self().SetProperty(mBlurStrengthPropertyIndex, blurStrength);
168 }
169
170 float SuperBlurView::GetCurrentBlurStrength() const
171 {
172   float blurStrength;
173   (Self().GetProperty( mBlurStrengthPropertyIndex )).Get(blurStrength);
174
175   return blurStrength;
176 }
177
178 Toolkit::SuperBlurView::SuperBlurViewSignal& SuperBlurView::BlurFinishedSignal()
179 {
180   return mBlurFinishedSignal;
181 }
182
183 Image SuperBlurView::GetBlurredImage( unsigned int level )
184 {
185   DALI_ASSERT_ALWAYS( level>0 && level<=mBlurLevels );
186   return mBlurredImage[level-1];
187 }
188
189 void SuperBlurView::BlurImage( unsigned int idx, Image image )
190 {
191   DALI_ASSERT_ALWAYS( mGaussianBlurView.size()>idx );
192   mGaussianBlurView[idx] = Toolkit::GaussianBlurView::New( GAUSSIAN_BLUR_DEFAULT_NUM_SAMPLES+GAUSSIAN_BLUR_NUM_SAMPLES_INCREMENTATION*idx,
193                                                            GAUSSIAN_BLUR_BELL_CURVE_WIDTH + GAUSSIAN_BLUR_BELL_CURVE_WIDTH_INCREMENTATION*static_cast<float>(idx),
194                                                            GAUSSIAN_BLUR_RENDER_TARGET_PIXEL_FORMAT,
195                                                            GAUSSIAN_BLUR_DOWNSAMPLE_WIDTH_SCALE, GAUSSIAN_BLUR_DOWNSAMPLE_HEIGHT_SCALE, true );
196   mGaussianBlurView[idx].SetParentOrigin(ParentOrigin::CENTER);
197   mGaussianBlurView[idx].SetSize(mTargetSize);
198   mGaussianBlurView[idx].SetUserImageAndOutputRenderTarget( image, mBlurredImage[idx] );
199   if( idx == mBlurLevels-1 )
200   {
201     mGaussianBlurView[idx].FinishedSignal().Connect( this, &SuperBlurView::OnBlurViewFinished );
202   }
203   Stage::GetCurrent().Add( mGaussianBlurView[idx] );
204   mGaussianBlurView[idx].ActivateOnce();
205 }
206
207 void SuperBlurView::OnBlurViewFinished( Toolkit::GaussianBlurView blurView )
208 {
209   ClearBlurResource();
210   Toolkit::SuperBlurView handle( GetOwner() );
211   mBlurFinishedSignal.Emit( handle );
212 }
213
214 void SuperBlurView::ClearBlurResource()
215 {
216   if( !mResourcesCleared )
217   {
218     DALI_ASSERT_ALWAYS( mGaussianBlurView.size() == mBlurLevels && "must synchronize the GaussianBlurView group if blur levels got changed " );
219     for(unsigned int i=0; i<mBlurLevels;i++)
220     {
221       Stage::GetCurrent().Remove( mGaussianBlurView[i] );
222       mGaussianBlurView[i].Deactivate();
223       mGaussianBlurView[i].Reset();
224     }
225     mResourcesCleared = true;
226   }
227 }
228
229 void SuperBlurView::OnRelaidOut( Vector2 size, ActorSizeContainer& container )
230 {
231   unsigned int numChildren = Self().GetChildCount();
232
233   for( unsigned int i=0; i<numChildren; ++i )
234   {
235     Self().GetChildAt(i).SetSize(size);
236   }
237 }
238
239 void SuperBlurView::OnControlSizeSet( const Vector3& targetSize )
240 {
241   if( mTargetSize != Vector2(targetSize) )
242   {
243     mTargetSize = Vector2(targetSize);
244
245     for(unsigned int i=0; i<mBlurLevels;i++)
246     {
247       float exponent = static_cast<float>(i+1);
248       mBlurredImage[i] = FrameBufferImage::New( mTargetSize.width/std::pow(2.f,exponent) , mTargetSize.height/std::pow(2.f,exponent),
249                                                 GAUSSIAN_BLUR_RENDER_TARGET_PIXEL_FORMAT, Dali::Image::Never );
250     }
251   }
252 }
253
254 } // namespace Internal
255
256 } // namespace Toolkit
257
258 } // namespace Dali