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