82ceb82e276790abf9dca711425f832a0b3950a1
[platform/core/uifw/dali-toolkit.git] / optional / 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
24 // INTERNAL INCLUDES
25
26 namespace Dali
27 {
28
29 namespace Toolkit
30 {
31
32 namespace Internal
33 {
34
35 namespace
36 {
37
38 const float DEFAULT_KERNEL0[] = { 12.0f/16.0f, 2.0f/16.0f, 2.0f/16.0f };
39
40 const float DEFAULT_KERNEL1[] = { 8.0f/16.0f, 2.75f/16.0f, 2.75f/16.0f, 1.25f/16.0f,
41                                   1.25f/16.0f };
42
43 const float DEFAULT_KERNEL2[] = { 5.0f/16.0f, 2.75f/16.0f, 2.75f/16.0f, 1.75f/16.0f,
44                                   1.75f/16.0f, 1.5f/16.0f, 1.5f/16.0f };
45
46 const float DEFAULT_KERNEL3[] = { 3.0f/16.0f, 2.0f/16.0f, 2.0f/16.0f, 2.0f/16.0f,
47                                   2.0f/16.0f, 2.0f/16.0f, 2.0f/16.0f, 0.5f/16.0f,
48                                   0.5f/16.0f };
49
50 const float DEFAULT_KERNEL4[] = { 2.0f/16.0f, 1.5f/16.0f, 1.5f/16.0f, 1.5f/16.0f,
51                                   1.5f/16.0f, 1.0f/16.0f, 1.0f/16.0f, 1.0f/16.0f,
52                                   1.0f/16.0f, 1.0f/16.0f, 1.0f/16.0f, 0.5f/16.0f,
53                                   0.5f/16.0f, 0.5f/16.0f, 0.5f/16.0f };
54
55
56 const float ARBITRARY_FIELD_OF_VIEW = Math::PI / 4.0f;
57
58 const char* BLUR_TWO_PASS_FRAGMENT_SOURCE =
59 {
60  "uniform vec2 uSampleOffsets[NUM_SAMPLES];\n"
61  "uniform float uSampleWeights[NUM_SAMPLES];\n"
62  "void main()\n"
63  "{\n"
64  "  vec4 color = vec4(0.0);\n"
65  "# ifdef DEBUG_RENDER\n"
66  "  if( vTexCoord.s < 0.495 )\n"
67  "  {\n"
68  "# endif //def DEBUG_RENDER\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  "# ifdef DEBUG_RENDER\n"
74  "  }\n"
75  "  else if( vTexCoord.s > 0.505 )\n"
76  "  {\n"
77  "    color = texture2D( sTexture, vTexCoord );\n"
78  "  }\n"
79  "  else\n"
80  "  {\n"
81  "    color = vec4( 1.0, 0.0, 0.0, 1.0 );\n"
82  "  }\n"
83  "# endif //def DEBUG_RENDER\n"
84  "  gl_FragColor = color;\n"
85  "}\n"
86 };
87
88 std::string GetOffsetUniformName( int index )
89 {
90   std::ostringstream oss;
91   oss << "uSampleOffsets[" << index << "]";
92   return oss.str();
93 }
94
95 std::string GetWeightUniformName( int index )
96 {
97   std::ostringstream oss;
98   oss << "uSampleWeights[" << index << "]";
99   return oss.str();
100 }
101
102 const char* BLEND_TWO_IMAGES_FRAGMENT_SOURCE =
103 {
104  "precision highp float;\n"
105  "uniform float uBlurStrength; \n "
106  "void main()\n"
107  "{\n"
108  "  gl_FragColor = texture2D( sTexture, vTexCoord ) * uBlurStrength"
109  "               + texture2D( sEffect, vTexCoord )*(1.0-uBlurStrength); \n"
110  "}\n"
111 };
112
113 std::string GetBlurStrengthUniformName()
114 {
115   return "uBlurStrength";
116 }
117
118 } // namespace
119
120
121 BlurTwoPassFilter::BlurTwoPassFilter()
122 : ImageFilter()
123 {
124   mShaderForBlending = ShaderEffect::New( "", BLEND_TWO_IMAGES_FRAGMENT_SOURCE );
125   mShaderForBlending.SetUniform( GetBlurStrengthUniformName(), 1.f );
126   mBlurStrengthPropertyIndex = mShaderForBlending.GetPropertyIndex( GetBlurStrengthUniformName() );
127 }
128
129 BlurTwoPassFilter::~BlurTwoPassFilter()
130 {
131 }
132
133 void BlurTwoPassFilter::Enable()
134 {
135   mCameraForBlur = CameraActor::New();
136   mCameraForBlur.SetParentOrigin(ParentOrigin::CENTER);
137
138   // create actor to render input with applied emboss effect
139   mActorForInput = ImageActor::New( mInputImage );
140   mActorForInput.SetParentOrigin( ParentOrigin::CENTER );
141   mActorForInput.ApplyConstraint( Constraint::New<Vector3>( Actor::SIZE, ParentSource( Actor::SIZE ), EqualToConstraint() ) );
142   mActorForInput.ScaleBy( Vector3(1.0f, -1.0f, 1.0f) );
143
144   // create internal offscreen for result of horizontal pass
145   mImageForHorz = FrameBufferImage::New( mTargetSize.width, mTargetSize.height, mPixelFormat, Image::Unused );
146
147   // create an actor to render mImageForHorz for vertical blur pass
148   mActorForHorz = ImageActor::New( mImageForHorz );
149   mActorForHorz.SetParentOrigin( ParentOrigin::CENTER );
150   mActorForHorz.ApplyConstraint( Constraint::New<Vector3>( Actor::SIZE, ParentSource( Actor::SIZE ), EqualToConstraint() ) );
151   mActorForHorz.ScaleBy( Vector3(1.0f, -1.0f, 1.0f) );
152
153   // create internal offscreen for result of the two pass blurred image
154   mBlurredImage = FrameBufferImage::New( mTargetSize.width, mTargetSize.height, mPixelFormat, Image::Unused );
155
156   // create an actor to blend the blurred image and the input image with the given blur strength
157   mActorForBlending = ImageActor::New( mBlurredImage );
158   mActorForBlending.SetParentOrigin( ParentOrigin::CENTER );
159   mActorForBlending.ApplyConstraint( Constraint::New<Vector3>( Actor::SIZE, ParentSource( Actor::SIZE ), EqualToConstraint() ) );
160   mActorForBlending.ScaleBy( Vector3(1.0f, -1.0f, 1.0f) );
161
162   mRootActor.Add( mActorForInput );
163   mRootActor.Add( mActorForHorz );
164   mRootActor.Add( mActorForBlending );
165   mRootActor.Add( mCameraForBlur );
166
167   // create custom shader effect
168   if( !GetKernelSize() )
169   {
170     CreateKernel( DEFAULT_KERNEL4, sizeof(DEFAULT_KERNEL4)/sizeof(DEFAULT_KERNEL4[0]) );
171   }
172   int kernelSize( static_cast< int >(GetKernelSize()) );
173
174   std::ostringstream fragmentSource;
175   if( mDebugRender )
176   {
177     fragmentSource << "#define DEBUG_RENDER\n";
178   }
179   fragmentSource << "#define NUM_SAMPLES " << kernelSize << "\n";
180   fragmentSource << BLUR_TWO_PASS_FRAGMENT_SOURCE;
181   mShaderForHorz = ShaderEffect::New( "", fragmentSource.str() );
182   mActorForInput.SetShaderEffect( mShaderForHorz );
183   mShaderForVert = ShaderEffect::New( "", fragmentSource.str() );
184   mActorForHorz.SetShaderEffect( mShaderForVert );
185
186   for( int i = 0; i < kernelSize; ++i )
187   {
188     const std::string offsetUniform( GetOffsetUniformName( i ) );
189     const std::string weightUniform( GetWeightUniformName( i ) );
190
191     mShaderForHorz.SetUniform( offsetUniform, Vector2(mKernel[i]) * Vector2::XAXIS );
192     mShaderForHorz.SetUniform( weightUniform, mKernel[i].z );
193
194     mShaderForVert.SetUniform( offsetUniform, Vector2(mKernel[i]) * Vector2::YAXIS );
195     mShaderForVert.SetUniform( weightUniform, mKernel[i].z );
196   }
197
198   mActorForBlending.SetShaderEffect( mShaderForBlending );
199   mShaderForBlending.SetEffectImage( mInputImage );
200
201   SetupCamera();
202   CreateRenderTasks();
203 }
204
205 void BlurTwoPassFilter::Disable()
206 {
207   if( mRootActor )
208   {
209     if( mCameraForBlur )
210     {
211       mRootActor.Remove( mCameraForBlur );
212       mCameraForBlur.Reset();
213     }
214
215     if( mActorForInput )
216     {
217       mRootActor.Remove( mActorForInput );
218       mActorForInput.Reset();
219     }
220
221     if( mActorForHorz )
222     {
223       mRootActor.Remove( mActorForHorz );
224       mActorForHorz.Reset();
225     }
226
227     if( mActorForBlending )
228     {
229       mRootActor.Remove( mActorForBlending );
230       mActorForBlending.Reset();
231     }
232
233     RenderTaskList taskList = Stage::GetCurrent().GetRenderTaskList();
234
235     if( mRenderTaskForHorz )
236     {
237       taskList.RemoveTask(mRenderTaskForHorz);
238     }
239     if( mRenderTaskForVert )
240     {
241       taskList.RemoveTask(mRenderTaskForVert);
242     }
243     if( mRenderTaskForBlending )
244     {
245       taskList.RemoveTask(mRenderTaskForBlending);
246     }
247
248     mRootActor.Reset();
249   }
250 }
251
252 void BlurTwoPassFilter::Refresh()
253 {
254   if( mRenderTaskForHorz )
255   {
256     mRenderTaskForHorz.SetRefreshRate( mRefreshOnDemand ? RenderTask::REFRESH_ONCE : RenderTask::REFRESH_ALWAYS );
257   }
258
259   if( mRenderTaskForVert )
260   {
261     mRenderTaskForVert.SetRefreshRate( mRefreshOnDemand ? RenderTask::REFRESH_ONCE : RenderTask::REFRESH_ALWAYS );
262   }
263
264   if( mRenderTaskForBlending )
265   {
266     mRenderTaskForBlending.SetRefreshRate( mRefreshOnDemand ? RenderTask::REFRESH_ONCE : RenderTask::REFRESH_ALWAYS );
267   }
268 }
269
270 Constrainable BlurTwoPassFilter::GetHandleForAnimateBlurStrength()
271 {
272   return mShaderForBlending;
273 }
274
275 void BlurTwoPassFilter::SetupCamera()
276 {
277   // Create and place a camera for the embossing render, corresponding to its render target size
278   mCameraForBlur.SetFieldOfView(ARBITRARY_FIELD_OF_VIEW);
279   mCameraForBlur.SetNearClippingPlane(1.0f);
280   mCameraForBlur.SetAspectRatio(mTargetSize.width / mTargetSize.height);
281   mCameraForBlur.SetType(Dali::Camera::FREE_LOOK); // camera orientation based solely on actor
282   mCameraForBlur.SetRotation(Quaternion(M_PI, Vector3::YAXIS));
283   mCameraForBlur.SetPosition(0.0f, 0.0f, ((mTargetSize.height * 0.5f) / tanf(ARBITRARY_FIELD_OF_VIEW * 0.5f)));
284 }
285
286 void BlurTwoPassFilter::CreateRenderTasks()
287 {
288   RenderTaskList taskList = Stage::GetCurrent().GetRenderTaskList();
289
290   // perform a horizontal blur targeting the internal buffer
291   mRenderTaskForHorz = taskList.CreateTask();
292   mRenderTaskForHorz.SetRefreshRate( mRefreshOnDemand ? RenderTask::REFRESH_ONCE : RenderTask::REFRESH_ALWAYS );
293   mRenderTaskForHorz.SetSourceActor( mActorForInput );
294   mRenderTaskForHorz.SetExclusive(true);
295   mRenderTaskForHorz.SetInputEnabled( false );
296   mRenderTaskForHorz.SetClearEnabled( true );
297   mRenderTaskForHorz.SetClearColor( mBackgroundColor );
298   mRenderTaskForHorz.SetTargetFrameBuffer( mImageForHorz );
299   mRenderTaskForHorz.SetCameraActor( mCameraForBlur );
300
301   // use the internal buffer and perform a horizontal blur targeting the output buffer
302   mRenderTaskForVert = taskList.CreateTask();
303   mRenderTaskForVert.SetRefreshRate( mRefreshOnDemand ? RenderTask::REFRESH_ONCE : RenderTask::REFRESH_ALWAYS );
304   mRenderTaskForVert.SetSourceActor( mActorForHorz );
305   mRenderTaskForVert.SetExclusive(true);
306   mRenderTaskForVert.SetInputEnabled( false );
307   mRenderTaskForVert.SetClearEnabled( true );
308   mRenderTaskForVert.SetClearColor( mBackgroundColor );
309   mRenderTaskForVert.SetTargetFrameBuffer( mBlurredImage );
310   mRenderTaskForVert.SetCameraActor( mCameraForBlur );
311
312   //Perform a blending between the blurred image and the input image
313   mRenderTaskForBlending = taskList.CreateTask();
314   mRenderTaskForBlending.SetRefreshRate( mRefreshOnDemand ? RenderTask::REFRESH_ONCE : RenderTask::REFRESH_ALWAYS );
315   mRenderTaskForBlending.SetSourceActor( mActorForBlending );
316   mRenderTaskForBlending.SetExclusive(true);
317   mRenderTaskForBlending.SetInputEnabled( false );
318   mRenderTaskForBlending.SetClearEnabled( true );
319   mRenderTaskForBlending.SetClearColor( mBackgroundColor );
320   mRenderTaskForBlending.SetTargetFrameBuffer( mOutputImage );
321   mRenderTaskForBlending.SetCameraActor( mCameraForBlur );
322 }
323
324 } // namespace Internal
325
326 } // namespace Toolkit
327
328 } // namespace Dali