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