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