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