Merge "Add new layouting support for TextLabel and ImageView." into devel/master
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / filters / blur-two-pass-filter.cpp
1 /*
2  * Copyright (c) 2017 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 "blur-two-pass-filter.h"
20
21 // EXTERNAL INCLUDES
22 #include <sstream>
23 #include <dali/public-api/animation/constraints.h>
24 #include <dali/public-api/common/stage.h>
25 #include <dali/public-api/object/property-map.h>
26 #include <dali/public-api/render-tasks/render-task-list.h>
27 #include <dali/public-api/rendering/renderer.h>
28 #include <dali/devel-api/images/texture-set-image.h>
29
30 // INTERNAL INCLUDES
31 #include <dali-toolkit/public-api/visuals/visual-properties.h>
32
33 namespace Dali
34 {
35
36 namespace Toolkit
37 {
38
39 namespace Internal
40 {
41
42 namespace
43 {
44
45 const float DEFAULT_KERNEL0[] = { 12.0f/16.0f, 2.0f/16.0f, 2.0f/16.0f };
46
47 const float DEFAULT_KERNEL1[] = { 8.0f/16.0f, 2.75f/16.0f, 2.75f/16.0f, 1.25f/16.0f,
48                                   1.25f/16.0f };
49
50 const float DEFAULT_KERNEL2[] = { 5.0f/16.0f, 2.75f/16.0f, 2.75f/16.0f, 1.75f/16.0f,
51                                   1.75f/16.0f, 1.5f/16.0f, 1.5f/16.0f };
52
53 const float DEFAULT_KERNEL3[] = { 3.0f/16.0f, 2.0f/16.0f, 2.0f/16.0f, 2.0f/16.0f,
54                                   2.0f/16.0f, 2.0f/16.0f, 2.0f/16.0f, 0.5f/16.0f,
55                                   0.5f/16.0f };
56
57 const float DEFAULT_KERNEL4[] = { 2.0f/16.0f, 1.5f/16.0f, 1.5f/16.0f, 1.5f/16.0f,
58                                   1.5f/16.0f, 1.0f/16.0f, 1.0f/16.0f, 1.0f/16.0f,
59                                   1.0f/16.0f, 1.0f/16.0f, 1.0f/16.0f, 0.5f/16.0f,
60                                   0.5f/16.0f, 0.5f/16.0f, 0.5f/16.0f };
61
62 const char* BLUR_TWO_PASS_FRAGMENT_SOURCE =
63 {
64  "precision highp float;\n"
65  "varying mediump vec2 vTexCoord;\n"
66  "uniform sampler2D sTexture;\n"
67  "uniform vec2 uSampleOffsets[NUM_SAMPLES];\n"
68  "uniform float uSampleWeights[NUM_SAMPLES];\n"
69  "void main()\n"
70  "{\n"
71  "  vec4 color = vec4(0.0);\n"
72  "  for( int i = 0; i < NUM_SAMPLES; ++i )\n"
73  "  {\n"
74  "    color += texture2D( sTexture, vTexCoord + uSampleOffsets[i] ) * uSampleWeights[i];\n"
75  "  }\n"
76  "  gl_FragColor = color;\n"
77  "}\n"
78 };
79
80 std::string GetOffsetUniformName( int index )
81 {
82   std::ostringstream oss;
83   oss << "uSampleOffsets[" << index << "]";
84   return oss.str();
85 }
86
87 std::string GetWeightUniformName( int index )
88 {
89   std::ostringstream oss;
90   oss << "uSampleWeights[" << index << "]";
91   return oss.str();
92 }
93
94 const char* BLEND_TWO_IMAGES_FRAGMENT_SOURCE =
95 {
96  "precision highp float;\n"
97  "uniform float uBlurStrength;\n "
98  "uniform sampler2D sTexture;\n"
99  "uniform sampler2D sEffect;\n"
100  "varying mediump vec2 vTexCoord;\n"
101  "void main()\n"
102  "{\n"
103  "  gl_FragColor = texture2D( sTexture, vTexCoord ) * uBlurStrength"
104  "               + texture2D( sEffect, vTexCoord )*(1.0-uBlurStrength); \n"
105  "}\n"
106 };
107
108 const char* const BLUR_STRENGTH_UNIFORM_NAME( "uBlurStrength"  );
109 const char* const EFFECT_IMAGE_NAME( "sEffect" );
110
111 } // namespace
112
113
114 BlurTwoPassFilter::BlurTwoPassFilter()
115 : ImageFilter()
116 {
117   // create blending actor and register the property in constructor
118   // to make sure that GetBlurStrengthPropertyIndex() always returns a valid index
119   mActorForBlending = Toolkit::ImageView::New();
120   mBlurStrengthPropertyIndex = mActorForBlending.RegisterProperty( BLUR_STRENGTH_UNIFORM_NAME, 1.f );
121 }
122
123 BlurTwoPassFilter::~BlurTwoPassFilter()
124 {
125 }
126
127 void BlurTwoPassFilter::Enable()
128 {
129   // create actor to render input with applied emboss effect
130   mActorForInput = Toolkit::ImageView::New( mInputImage );
131   mActorForInput.SetParentOrigin( ParentOrigin::CENTER );
132   mActorForInput.SetSize( mTargetSize );
133
134   // create internal offscreen for result of horizontal pass
135   mImageForHorz = FrameBufferImage::New( mTargetSize.width, mTargetSize.height, mPixelFormat );
136   // create an actor to render mImageForHorz for vertical blur pass
137   mActorForHorz = Toolkit::ImageView::New( mImageForHorz );
138   mActorForHorz.SetParentOrigin( ParentOrigin::CENTER );
139   mActorForHorz.SetSize( mTargetSize );
140
141   // create internal offscreen for result of the two pass blurred image
142   mBlurredImage = FrameBufferImage::New( mTargetSize.width, mTargetSize.height, mPixelFormat );
143   // create an actor to blend the blurred image and the input image with the given blur strength
144   mActorForBlending.SetImage( mBlurredImage );
145   mActorForBlending.SetParentOrigin( ParentOrigin::CENTER );
146   mActorForBlending.SetSize( mTargetSize );
147
148   // create custom shader effect
149   if( !GetKernelSize() )
150   {
151     CreateKernel( DEFAULT_KERNEL4, sizeof(DEFAULT_KERNEL4)/sizeof(DEFAULT_KERNEL4[0]) );
152   }
153   int kernelSize( static_cast< int >(GetKernelSize()) );
154
155   for( int i = 0; i < kernelSize; ++i )
156   {
157     const std::string offsetUniform( GetOffsetUniformName( i ) );
158     const std::string weightUniform( GetWeightUniformName( i ) );
159
160     mActorForInput.RegisterProperty( offsetUniform, Vector2(mKernel[i]) * Vector2::XAXIS );
161     mActorForInput.RegisterProperty( weightUniform, mKernel[i].z );
162
163     mActorForHorz.RegisterProperty( offsetUniform, Vector2(mKernel[i]) * Vector2::YAXIS );
164     mActorForHorz.RegisterProperty( weightUniform, mKernel[i].z );
165   }
166
167   // Set up blur-two-pass custom shader
168   std::ostringstream fragmentSource;
169   fragmentSource << "#define NUM_SAMPLES " << kernelSize << "\n";
170   fragmentSource << BLUR_TWO_PASS_FRAGMENT_SOURCE;
171
172   Property::Map customShader;
173   customShader[ Toolkit::Visual::Shader::Property::FRAGMENT_SHADER ] = fragmentSource.str();
174   Property::Map visualMap;
175   visualMap.Insert( Toolkit::Visual::Property::SHADER, customShader );
176   mActorForInput.SetProperty( Toolkit::ImageView::Property::IMAGE, visualMap );
177   mActorForHorz.SetProperty( Toolkit::ImageView::Property::IMAGE, visualMap );
178
179   // Set up blend-two-image custom shader
180   customShader[ Toolkit::Visual::Shader::Property::FRAGMENT_SHADER ] = BLEND_TWO_IMAGES_FRAGMENT_SOURCE;
181   visualMap[ Toolkit::Visual::Property::SHADER ] = customShader;
182   mActorForBlending.SetProperty( Toolkit::ImageView::Property::IMAGE, visualMap );
183
184   mRootActor.Add( mActorForInput );
185   mRootActor.Add( mActorForHorz );
186   mRootActor.Add( mActorForBlending );
187
188   // Add effect texture to blend-two-image custom shader
189   TextureSet textureSet = mActorForBlending.GetRendererAt(0).GetTextures();
190   if( textureSet )
191   {
192     TextureSetImage( textureSet, 1u, mInputImage );
193   }
194
195   SetupCamera();
196   CreateRenderTasks();
197 }
198
199 void BlurTwoPassFilter::Disable()
200 {
201   if( mRootActor )
202   {
203     if( mCameraActor )
204     {
205       mRootActor.Remove( mCameraActor );
206       mCameraActor.Reset();
207     }
208
209     if( mActorForInput )
210     {
211       mRootActor.Remove( mActorForInput );
212       mActorForInput.Reset();
213     }
214
215     if( mActorForHorz )
216     {
217       mRootActor.Remove( mActorForHorz );
218       mActorForHorz.Reset();
219     }
220
221     RenderTaskList taskList = Stage::GetCurrent().GetRenderTaskList();
222
223     if( mRenderTaskForHorz )
224     {
225       taskList.RemoveTask(mRenderTaskForHorz);
226     }
227     if( mRenderTaskForVert )
228     {
229       taskList.RemoveTask(mRenderTaskForVert);
230     }
231     if( mRenderTaskForBlending )
232     {
233       taskList.RemoveTask(mRenderTaskForBlending);
234     }
235
236     mRootActor.Reset();
237   }
238 }
239
240 void BlurTwoPassFilter::Refresh()
241 {
242   if( mRenderTaskForHorz )
243   {
244     mRenderTaskForHorz.SetRefreshRate( mRefreshOnDemand ? RenderTask::REFRESH_ONCE : RenderTask::REFRESH_ALWAYS );
245   }
246
247   if( mRenderTaskForVert )
248   {
249     mRenderTaskForVert.SetRefreshRate( mRefreshOnDemand ? RenderTask::REFRESH_ONCE : RenderTask::REFRESH_ALWAYS );
250   }
251
252   if( mRenderTaskForBlending )
253   {
254     mRenderTaskForBlending.SetRefreshRate( mRefreshOnDemand ? RenderTask::REFRESH_ONCE : RenderTask::REFRESH_ALWAYS );
255   }
256 }
257
258 void BlurTwoPassFilter::SetSize( const Vector2& size )
259 {
260   mTargetSize = size;
261   if( mActorForInput )
262   {
263     mActorForInput.SetSize(mTargetSize);
264   }
265   if( mActorForHorz )
266   {
267     mActorForHorz.SetSize(mTargetSize);
268   }
269   if( mActorForBlending )
270   {
271     mActorForBlending.SetSize(mTargetSize);
272   }
273 }
274
275 Handle BlurTwoPassFilter::GetHandleForAnimateBlurStrength()
276 {
277   return mActorForBlending;
278 }
279
280 void BlurTwoPassFilter::CreateRenderTasks()
281 {
282   RenderTaskList taskList = Stage::GetCurrent().GetRenderTaskList();
283
284   // perform a horizontal blur targeting the internal buffer
285   mRenderTaskForHorz = taskList.CreateTask();
286   mRenderTaskForHorz.SetRefreshRate( mRefreshOnDemand ? RenderTask::REFRESH_ONCE : RenderTask::REFRESH_ALWAYS );
287   mRenderTaskForHorz.SetSourceActor( mActorForInput );
288   mRenderTaskForHorz.SetExclusive(true);
289   mRenderTaskForHorz.SetInputEnabled( false );
290   mRenderTaskForHorz.SetClearEnabled( true );
291   mRenderTaskForHorz.SetClearColor( mBackgroundColor );
292   mRenderTaskForHorz.SetTargetFrameBuffer( mImageForHorz );
293   mRenderTaskForHorz.SetCameraActor( mCameraActor );
294
295   // use the internal buffer and perform a horizontal blur targeting the output buffer
296   mRenderTaskForVert = taskList.CreateTask();
297   mRenderTaskForVert.SetRefreshRate( mRefreshOnDemand ? RenderTask::REFRESH_ONCE : RenderTask::REFRESH_ALWAYS );
298   mRenderTaskForVert.SetSourceActor( mActorForHorz );
299   mRenderTaskForVert.SetExclusive(true);
300   mRenderTaskForVert.SetInputEnabled( false );
301   mRenderTaskForVert.SetClearEnabled( true );
302   mRenderTaskForVert.SetClearColor( mBackgroundColor );
303   mRenderTaskForVert.SetTargetFrameBuffer( mBlurredImage );
304   mRenderTaskForVert.SetCameraActor( mCameraActor );
305
306   //Perform a blending between the blurred image and the input image
307   mRenderTaskForBlending = taskList.CreateTask();
308   mRenderTaskForBlending.SetRefreshRate( mRefreshOnDemand ? RenderTask::REFRESH_ONCE : RenderTask::REFRESH_ALWAYS );
309   mRenderTaskForBlending.SetSourceActor( mActorForBlending );
310   mRenderTaskForBlending.SetExclusive(true);
311   mRenderTaskForBlending.SetInputEnabled( false );
312   mRenderTaskForBlending.SetClearEnabled( true );
313   mRenderTaskForBlending.SetClearColor( mBackgroundColor );
314   mRenderTaskForBlending.SetTargetFrameBuffer( mOutputImage );
315   mRenderTaskForBlending.SetCameraActor( mCameraActor );
316 }
317
318 } // namespace Internal
319
320 } // namespace Toolkit
321
322 } // namespace Dali