Merge "Fix documentation for Text::EditableControlInterface interface override functi...
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / controls / super-blur-view / super-blur-view-impl.cpp
1 /*
2  * Copyright (c) 2020 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/devel-api/common/stage.h>
25 #include <dali/public-api/object/property-map.h>
26 #include <dali/public-api/object/type-registry.h>
27 #include <dali/public-api/object/type-registry-helper.h>
28 #include <dali/public-api/rendering/renderer.h>
29 #include <dali/devel-api/scripting/scripting.h>
30 #include <dali/integration-api/debug.h>
31
32 // INTERNAL_INCLUDES
33 #include <dali-toolkit/public-api/image-loader/sync-image-loader.h>
34 #include <dali-toolkit/devel-api/controls/control-devel.h>
35 #include <dali-toolkit/internal/controls/control/control-renderers.h>
36 #include <dali-toolkit/internal/visuals/visual-base-impl.h>
37 #include <dali-toolkit/internal/visuals/visual-factory-impl.h>
38
39 namespace //Unnamed namespace
40 {
41
42 using namespace Dali;
43
44 //Todo: make these properties instead of constants
45 const unsigned int GAUSSIAN_BLUR_DEFAULT_NUM_SAMPLES = 11;
46 const unsigned int GAUSSIAN_BLUR_NUM_SAMPLES_INCREMENTATION = 10;
47 const float GAUSSIAN_BLUR_BELL_CURVE_WIDTH = 4.5f;
48 const float GAUSSIAN_BLUR_BELL_CURVE_WIDTH_INCREMENTATION = 5.f;
49 const Pixel::Format GAUSSIAN_BLUR_RENDER_TARGET_PIXEL_FORMAT = Pixel::RGBA8888;
50 const float GAUSSIAN_BLUR_DOWNSAMPLE_WIDTH_SCALE = 0.5f;
51 const float GAUSSIAN_BLUR_DOWNSAMPLE_HEIGHT_SCALE = 0.5f;
52
53 const char* ALPHA_UNIFORM_NAME( "uAlpha" );
54 const char* FRAGMENT_SHADER = DALI_COMPOSE_SHADER(
55   varying mediump vec2 vTexCoord;\n
56   uniform sampler2D sTexture;\n
57   uniform lowp vec4 uColor;\n
58   uniform lowp float uAlpha;\n
59   \n
60   void main()\n
61   {\n
62     gl_FragColor = texture2D( sTexture, vTexCoord ) * uColor;\n
63     gl_FragColor.a *= uAlpha;
64   }\n
65 );
66
67 /**
68  * 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.
69  */
70 struct ActorOpacityConstraint
71 {
72   ActorOpacityConstraint(int totalImageNum, int currentImageIdx)
73   {
74     float rangeLength = 1.f / static_cast<float>( totalImageNum );
75     float index = static_cast<float>( currentImageIdx );
76     mRange = Vector2( index*rangeLength, (index+1.f)*rangeLength );
77   }
78
79   void operator()( float& current, const PropertyInputContainer& inputs )
80   {
81     float blurStrength = inputs[0]->GetFloat();
82     if(blurStrength < mRange.x)
83     {
84       current = 0.f;
85     }
86     else if(blurStrength > mRange.y)
87     {
88       current = 1.f;
89     }
90     else
91     {
92       current = ( blurStrength - mRange.x) / ( mRange.y - mRange.x );
93     }
94   }
95
96   Vector2 mRange;
97 };
98
99 } // namespace
100
101 namespace Dali
102 {
103
104 namespace Toolkit
105 {
106
107 namespace Internal
108 {
109
110 namespace
111 {
112
113 const unsigned int DEFAULT_BLUR_LEVEL(5u); ///< The default blur level when creating SuperBlurView from the type registry
114
115 BaseHandle Create()
116 {
117   return Toolkit::SuperBlurView::New( DEFAULT_BLUR_LEVEL );
118 }
119
120 // Setup properties, signals and actions using the type-registry.
121 DALI_TYPE_REGISTRATION_BEGIN( Toolkit::SuperBlurView, Toolkit::Control, Create )
122
123 DALI_PROPERTY_REGISTRATION( Toolkit, SuperBlurView, "imageUrl", STRING, IMAGE_URL )
124
125 DALI_TYPE_REGISTRATION_END()
126
127 } // unnamed namespace
128
129 SuperBlurView::SuperBlurView( unsigned int blurLevels )
130 : Control( ControlBehaviour( DISABLE_SIZE_NEGOTIATION | DISABLE_STYLE_CHANGE_SIGNALS ) ),
131   mTargetSize( Vector2::ZERO ),
132   mBlurStrengthPropertyIndex(Property::INVALID_INDEX),
133   mBlurLevels( blurLevels ),
134   mResourcesCleared( true )
135 {
136   DALI_ASSERT_ALWAYS( mBlurLevels > 0 && " Minimal blur level is one, otherwise no blur is needed" );
137   mGaussianBlurView.assign( blurLevels, Toolkit::GaussianBlurView() );
138   mBlurredImage.assign( blurLevels, FrameBuffer() );
139   mRenderers.assign( blurLevels+1, Dali::Renderer() );
140 }
141
142 SuperBlurView::~SuperBlurView()
143 {
144 }
145
146 Toolkit::SuperBlurView SuperBlurView::New( unsigned int blurLevels )
147 {
148   //Create the implementation
149   IntrusivePtr<SuperBlurView> superBlurView( new SuperBlurView( blurLevels ) );
150
151   //Pass ownership to CustomActor via derived handle
152   Toolkit::SuperBlurView handle( *superBlurView );
153
154   // Second-phase init of the implementation
155   // This can only be done after the CustomActor connection has been made...
156   superBlurView->Initialize();
157
158   return handle;
159 }
160
161 void SuperBlurView::OnInitialize()
162 {
163   Actor self( Self() );
164
165   mBlurStrengthPropertyIndex = self.RegisterProperty( "blurStrength", 0.f );
166 }
167
168 void SuperBlurView::SetTexture( Texture texture )
169 {
170   mInputTexture = texture;
171
172   if( mTargetSize == Vector2::ZERO )
173   {
174     return;
175   }
176
177   ClearBlurResource();
178
179   Actor self( Self() );
180
181   BlurTexture( 0, mInputTexture );
182   SetRendererTexture( mRenderers[0], texture );
183
184   unsigned int i = 1;
185   for(; i<mBlurLevels; i++)
186   {
187     BlurTexture( i, mBlurredImage[i-1].GetColorTexture() );
188     SetRendererTexture( mRenderers[i], mBlurredImage[i-1] );
189   }
190
191   SetRendererTexture( mRenderers[i], mBlurredImage[i-1] );
192
193   mResourcesCleared = false;
194 }
195
196 Property::Index SuperBlurView::GetBlurStrengthPropertyIndex() const
197 {
198   return mBlurStrengthPropertyIndex;
199 }
200
201 void SuperBlurView::SetBlurStrength( float blurStrength )
202 {
203   Self().SetProperty(mBlurStrengthPropertyIndex, blurStrength);
204 }
205
206 float SuperBlurView::GetCurrentBlurStrength() const
207 {
208   float blurStrength;
209   (Self().GetProperty( mBlurStrengthPropertyIndex )).Get(blurStrength);
210
211   return blurStrength;
212 }
213
214 Toolkit::SuperBlurView::SuperBlurViewSignal& SuperBlurView::BlurFinishedSignal()
215 {
216   return mBlurFinishedSignal;
217 }
218
219 Texture SuperBlurView::GetBlurredTexture( unsigned int level )
220 {
221   DALI_ASSERT_ALWAYS( level>0 && level<=mBlurLevels );
222
223   FrameBuffer frameBuffer = mBlurredImage[level-1];
224
225   return frameBuffer.GetColorTexture();
226 }
227
228 void SuperBlurView::BlurTexture( unsigned int idx, Texture texture )
229 {
230   DALI_ASSERT_ALWAYS( mGaussianBlurView.size()>idx );
231   mGaussianBlurView[idx] = Toolkit::GaussianBlurView::New( GAUSSIAN_BLUR_DEFAULT_NUM_SAMPLES+GAUSSIAN_BLUR_NUM_SAMPLES_INCREMENTATION*idx,
232                                                            GAUSSIAN_BLUR_BELL_CURVE_WIDTH + GAUSSIAN_BLUR_BELL_CURVE_WIDTH_INCREMENTATION*static_cast<float>(idx),
233                                                            GAUSSIAN_BLUR_RENDER_TARGET_PIXEL_FORMAT,
234                                                            GAUSSIAN_BLUR_DOWNSAMPLE_WIDTH_SCALE, GAUSSIAN_BLUR_DOWNSAMPLE_HEIGHT_SCALE, true );
235   mGaussianBlurView[idx].SetProperty( Actor::Property::PARENT_ORIGIN,ParentOrigin::CENTER );
236   mGaussianBlurView[idx].SetProperty( Actor::Property::SIZE, mTargetSize );
237   Stage::GetCurrent().Add( mGaussianBlurView[idx] );
238
239   mGaussianBlurView[idx].SetUserImageAndOutputRenderTarget( texture, mBlurredImage[idx] );
240
241   mGaussianBlurView[idx].ActivateOnce();
242   if( idx == mBlurLevels-1 )
243   {
244     mGaussianBlurView[idx].FinishedSignal().Connect( this, &SuperBlurView::OnBlurViewFinished );
245   }
246 }
247
248 void SuperBlurView::OnBlurViewFinished( Toolkit::GaussianBlurView blurView )
249 {
250   ClearBlurResource();
251   Toolkit::SuperBlurView handle( GetOwner() );
252   mBlurFinishedSignal.Emit( handle );
253 }
254
255 void SuperBlurView::ClearBlurResource()
256 {
257   if( !mResourcesCleared )
258   {
259     DALI_ASSERT_ALWAYS( mGaussianBlurView.size() == mBlurLevels && "must synchronize the GaussianBlurView group if blur levels got changed " );
260     for(unsigned int i=0; i<mBlurLevels;i++)
261     {
262       Stage::GetCurrent().Remove( mGaussianBlurView[i] );
263       mGaussianBlurView[i].Deactivate();
264     }
265     mResourcesCleared = true;
266   }
267 }
268
269 void SuperBlurView::OnSizeSet( const Vector3& targetSize )
270 {
271   if( mTargetSize != Vector2(targetSize) )
272   {
273     mTargetSize = Vector2(targetSize);
274
275     Actor self = Self();
276     for( unsigned int i = 1; i <= mBlurLevels; i++ )
277     {
278       float exponent = static_cast<float>(i);
279
280       unsigned int width = mTargetSize.width/std::pow(2.f,exponent);
281       unsigned int height = mTargetSize.height/std::pow(2.f,exponent);
282
283       mBlurredImage[i-1] = FrameBuffer::New( width, height, FrameBuffer::Attachment::NONE );
284       Texture texture = Texture::New( TextureType::TEXTURE_2D, GAUSSIAN_BLUR_RENDER_TARGET_PIXEL_FORMAT, unsigned(width), unsigned(height) );
285       mBlurredImage[i-1].AttachColorTexture( texture );
286     }
287
288     if( mInputTexture )
289     {
290       SetTexture( mInputTexture );
291     }
292   }
293
294   Control::OnSizeSet( targetSize );
295 }
296
297 void SuperBlurView::OnSceneConnection( int depth )
298 {
299   if( mTargetSize == Vector2::ZERO )
300   {
301     return;
302   }
303
304   // Exception to the rule, chaining up first ensures visuals have SetOnScene called to create their renderers
305   Control::OnSceneConnection( depth );
306
307   Actor self = Self();
308
309   for(unsigned int i=0; i<mBlurLevels+1;i++)
310   {
311     mRenderers[i] = CreateRenderer( BASIC_VERTEX_SOURCE, FRAGMENT_SHADER );
312     mRenderers[i].SetProperty( Dali::Renderer::Property::DEPTH_INDEX, (int)i );
313     self.AddRenderer( mRenderers[i] );
314
315     if( i > 0 )
316     {
317       Renderer renderer = mRenderers[i];
318       Property::Index index = renderer.RegisterProperty( ALPHA_UNIFORM_NAME, 0.f );
319       Constraint constraint = Constraint::New<float>( renderer, index, ActorOpacityConstraint(mBlurLevels, i-1) );
320       constraint.AddSource( Source( self, mBlurStrengthPropertyIndex ) );
321       constraint.Apply();
322     }
323   }
324
325   if( mInputTexture )
326   {
327     SetRendererTexture( mRenderers[0], mInputTexture );
328     unsigned int i = 1;
329     for(; i<mBlurLevels; i++)
330     {
331       SetRendererTexture( mRenderers[i], mBlurredImage[i-1] );
332     }
333     SetRendererTexture( mRenderers[i], mBlurredImage[i-1] );
334   }
335 }
336
337 void SuperBlurView::OnSceneDisconnection()
338 {
339   for(unsigned int i=0; i<mBlurLevels+1;i++)
340   {
341     Self().RemoveRenderer( mRenderers[i] );
342     mRenderers[i].Reset();
343   }
344
345   Control::OnSceneDisconnection();
346 }
347
348 Vector3 SuperBlurView::GetNaturalSize()
349 {
350   if( mInputTexture )
351   {
352     return Vector3( mInputTexture.GetWidth(), mInputTexture.GetHeight(), 0.f );
353   }
354   return Vector3::ZERO;
355 }
356
357 void SuperBlurView::SetProperty( BaseObject* object, Property::Index propertyIndex, const Property::Value& value )
358 {
359   Toolkit::SuperBlurView superBlurView = Toolkit::SuperBlurView::DownCast( Dali::BaseHandle( object ) );
360
361   if( superBlurView )
362   {
363     SuperBlurView& superBlurViewImpl( GetImpl( superBlurView ) );
364
365     if( propertyIndex == Toolkit::SuperBlurView::Property::IMAGE_URL )
366     {
367       value.Get( superBlurViewImpl.mUrl );
368
369       PixelData pixels = SyncImageLoader::Load( superBlurViewImpl.mUrl );
370
371       if ( pixels )
372       {
373         Texture texture = Texture::New( TextureType::TEXTURE_2D, pixels.GetPixelFormat(), pixels.GetWidth(), pixels.GetHeight() );
374         texture.Upload( pixels, 0, 0, 0, 0, pixels.GetWidth(), pixels.GetHeight() );
375
376         superBlurViewImpl.SetTexture( texture );
377       }
378       else
379       {
380         DALI_LOG_ERROR( "Cannot create image from property value\n" );
381       }
382     }
383   }
384 }
385
386 Property::Value SuperBlurView::GetProperty( BaseObject* object, Property::Index propertyIndex )
387 {
388   Property::Value value;
389
390   Toolkit::SuperBlurView blurView = Toolkit::SuperBlurView::DownCast( Dali::BaseHandle( object ) );
391
392   if( blurView )
393   {
394     SuperBlurView& superBlurViewImpl( GetImpl( blurView ) );
395
396     if( propertyIndex == Toolkit::SuperBlurView::Property::IMAGE_URL )
397     {
398       value = superBlurViewImpl.mUrl;
399     }
400   }
401
402   return value;
403 }
404
405 } // namespace Internal
406
407 } // namespace Toolkit
408
409 } // namespace Dali