3a258f19b9e437223088c5e944d9c971fe2c3494
[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 // INTERNAL INCLUDES
31 #include <dali-toolkit/devel-api/visuals/visual-properties-devel.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::DevelVisual::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::DevelVisual::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   TextureSetImage( textureSet, 1u, mInputImage );
191
192   SetupCamera();
193   CreateRenderTasks();
194 }
195
196 void BlurTwoPassFilter::Disable()
197 {
198   if( mRootActor )
199   {
200     if( mCameraActor )
201     {
202       mRootActor.Remove( mCameraActor );
203       mCameraActor.Reset();
204     }
205
206     if( mActorForInput )
207     {
208       mRootActor.Remove( mActorForInput );
209       mActorForInput.Reset();
210     }
211
212     if( mActorForHorz )
213     {
214       mRootActor.Remove( mActorForHorz );
215       mActorForHorz.Reset();
216     }
217
218     RenderTaskList taskList = Stage::GetCurrent().GetRenderTaskList();
219
220     if( mRenderTaskForHorz )
221     {
222       taskList.RemoveTask(mRenderTaskForHorz);
223     }
224     if( mRenderTaskForVert )
225     {
226       taskList.RemoveTask(mRenderTaskForVert);
227     }
228     if( mRenderTaskForBlending )
229     {
230       taskList.RemoveTask(mRenderTaskForBlending);
231     }
232
233     mRootActor.Reset();
234   }
235 }
236
237 void BlurTwoPassFilter::Refresh()
238 {
239   if( mRenderTaskForHorz )
240   {
241     mRenderTaskForHorz.SetRefreshRate( mRefreshOnDemand ? RenderTask::REFRESH_ONCE : RenderTask::REFRESH_ALWAYS );
242   }
243
244   if( mRenderTaskForVert )
245   {
246     mRenderTaskForVert.SetRefreshRate( mRefreshOnDemand ? RenderTask::REFRESH_ONCE : RenderTask::REFRESH_ALWAYS );
247   }
248
249   if( mRenderTaskForBlending )
250   {
251     mRenderTaskForBlending.SetRefreshRate( mRefreshOnDemand ? RenderTask::REFRESH_ONCE : RenderTask::REFRESH_ALWAYS );
252   }
253 }
254
255 void BlurTwoPassFilter::SetSize( const Vector2& size )
256 {
257   mTargetSize = size;
258   if( mActorForInput )
259   {
260     mActorForInput.SetSize(mTargetSize);
261   }
262   if( mActorForHorz )
263   {
264     mActorForHorz.SetSize(mTargetSize);
265   }
266   if( mActorForBlending )
267   {
268     mActorForBlending.SetSize(mTargetSize);
269   }
270 }
271
272 Handle BlurTwoPassFilter::GetHandleForAnimateBlurStrength()
273 {
274   return mActorForBlending;
275 }
276
277 void BlurTwoPassFilter::CreateRenderTasks()
278 {
279   RenderTaskList taskList = Stage::GetCurrent().GetRenderTaskList();
280
281   // perform a horizontal blur targeting the internal buffer
282   mRenderTaskForHorz = taskList.CreateTask();
283   mRenderTaskForHorz.SetRefreshRate( mRefreshOnDemand ? RenderTask::REFRESH_ONCE : RenderTask::REFRESH_ALWAYS );
284   mRenderTaskForHorz.SetSourceActor( mActorForInput );
285   mRenderTaskForHorz.SetExclusive(true);
286   mRenderTaskForHorz.SetInputEnabled( false );
287   mRenderTaskForHorz.SetClearEnabled( true );
288   mRenderTaskForHorz.SetClearColor( mBackgroundColor );
289   mRenderTaskForHorz.SetTargetFrameBuffer( mImageForHorz );
290   mRenderTaskForHorz.SetCameraActor( mCameraActor );
291
292   // use the internal buffer and perform a horizontal blur targeting the output buffer
293   mRenderTaskForVert = taskList.CreateTask();
294   mRenderTaskForVert.SetRefreshRate( mRefreshOnDemand ? RenderTask::REFRESH_ONCE : RenderTask::REFRESH_ALWAYS );
295   mRenderTaskForVert.SetSourceActor( mActorForHorz );
296   mRenderTaskForVert.SetExclusive(true);
297   mRenderTaskForVert.SetInputEnabled( false );
298   mRenderTaskForVert.SetClearEnabled( true );
299   mRenderTaskForVert.SetClearColor( mBackgroundColor );
300   mRenderTaskForVert.SetTargetFrameBuffer( mBlurredImage );
301   mRenderTaskForVert.SetCameraActor( mCameraActor );
302
303   //Perform a blending between the blurred image and the input image
304   mRenderTaskForBlending = taskList.CreateTask();
305   mRenderTaskForBlending.SetRefreshRate( mRefreshOnDemand ? RenderTask::REFRESH_ONCE : RenderTask::REFRESH_ALWAYS );
306   mRenderTaskForBlending.SetSourceActor( mActorForBlending );
307   mRenderTaskForBlending.SetExclusive(true);
308   mRenderTaskForBlending.SetInputEnabled( false );
309   mRenderTaskForBlending.SetClearEnabled( true );
310   mRenderTaskForBlending.SetClearColor( mBackgroundColor );
311   mRenderTaskForBlending.SetTargetFrameBuffer( mOutputImage );
312   mRenderTaskForBlending.SetCameraActor( mCameraActor );
313 }
314
315 } // namespace Internal
316
317 } // namespace Toolkit
318
319 } // namespace Dali