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