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