Merge "Text - Initialize the mUpdateCursorHookPosition member in the constructor...
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / controls / gaussian-blur-view / gaussian-blur-view-impl.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 "gaussian-blur-view-impl.h"
20
21 // EXTERNAL INCLUDES
22 #include <sstream>
23 #include <iomanip>
24 #include <dali/public-api/animation/constraint.h>
25 #include <dali/public-api/animation/constraints.h>
26 #include <dali/public-api/common/stage.h>
27 #include <dali/public-api/object/type-registry.h>
28 #include <dali/public-api/object/type-registry-helper.h>
29 #include <dali/public-api/render-tasks/render-task-list.h>
30 #include <dali/integration-api/debug.h>
31
32 // INTERNAL INCLUDES
33 #include <dali-toolkit/devel-api/visual-factory/devel-visual-properties.h>
34
35 // TODO:
36 // pixel format / size - set from JSON
37 // aspect ratio property needs to be able to be constrained also for cameras, not possible currently. Therefore changing aspect ratio of GaussianBlurView won't currently work
38 // default near clip value
39 // Manager object - re-use render targets if there are multiple GaussianBlurViews created
40
41
42 /////////////////////////////////////////////////////////
43 // IMPLEMENTATION NOTES
44
45 // As the GaussianBlurView actor changes size, the amount of pixels we need to blur changes. Therefore we need some way of doing this. However:-
46 // OnSetSize() does not get called when GaussianBlurView object size is modified using a Constraint.
47 // OnSizeAnimation() only gets called once per AnimateTo/By() and if an Animation has N such calls then only the final one will end up being used. Therefore we can't use
48 // OnSizeAnimation() to alter render target sizes.
49 // To get around the above problems, we use fixed sized render targets, from the last SetSize() call (which calls OnSetSize()), then we adjust the internal cameras / actors
50 // to take account of the changed GaussianBlurView object size, projecting to the unchanged render target sizes. This is done relative to the fixed render target / actor sizes
51 // by using constraints relative to the GaussianBlurView actor size.
52
53
54 // 2 modes:
55 // 1st mode, this control has a tree of actors (use Add() to add children) that are rendered and blurred.
56 // mRenderChildrenTask renders children to FB mRenderTargetForRenderingChildren
57 // mHorizBlurTask renders mImageViewHorizBlur Actor showing FB mRenderTargetForRenderingChildren into FB mRenderTarget2
58 // mVertBlurTask renders mImageViewVertBlur Actor showing FB mRenderTarget2 into FB mRenderTarget1
59 // mCompositeTask renders mImageViewComposite Actor showing FB mRenderTarget1 into FB mRenderTargetForRenderingChildren
60 //
61 // 2nd mode, an image is blurred and rendered to a supplied target framebuffer
62 // mHorizBlurTask renders mImageViewHorizBlur Actor showing mUserInputImage into FB mRenderTarget2
63 // mVertBlurTask renders mImageViewVertBlur Actor showing mRenderTarget2 into FB mUserOutputRenderTarget
64 //
65 // Only this 2nd mode handles ActivateOnce
66
67 namespace Dali
68 {
69
70 namespace Toolkit
71 {
72
73 namespace Internal
74 {
75
76 namespace
77 {
78
79 using namespace Dali;
80
81 BaseHandle Create()
82 {
83   return Toolkit::GaussianBlurView::New();
84 }
85
86 DALI_TYPE_REGISTRATION_BEGIN( Toolkit::GaussianBlurView, Toolkit::Control, Create )
87 DALI_TYPE_REGISTRATION_END()
88
89 const unsigned int GAUSSIAN_BLUR_VIEW_DEFAULT_NUM_SAMPLES = 5;
90 const float GAUSSIAN_BLUR_VIEW_DEFAULT_BLUR_BELL_CURVE_WIDTH = 1.5f;
91 const Pixel::Format GAUSSIAN_BLUR_VIEW_DEFAULT_RENDER_TARGET_PIXEL_FORMAT = Pixel::RGBA8888;
92 const float GAUSSIAN_BLUR_VIEW_DEFAULT_BLUR_STRENGTH = 1.0f;                                       // default, fully blurred
93 const char* const GAUSSIAN_BLUR_VIEW_STRENGTH_PROPERTY_NAME = "GaussianBlurStrengthPropertyName";
94 const float GAUSSIAN_BLUR_VIEW_DEFAULT_DOWNSAMPLE_WIDTH_SCALE = 0.5f;
95 const float GAUSSIAN_BLUR_VIEW_DEFAULT_DOWNSAMPLE_HEIGHT_SCALE = 0.5f;
96
97 const float ARBITRARY_FIELD_OF_VIEW = Math::PI / 4.0f;
98
99 const char* const GAUSSIAN_BLUR_FRAGMENT_SOURCE =
100     "varying mediump vec2 vTexCoord;\n"
101     "uniform sampler2D sTexture;\n"
102     "uniform lowp vec4 uColor;\n"
103     "uniform mediump vec2 uSampleOffsets[NUM_SAMPLES];\n"
104     "uniform mediump float uSampleWeights[NUM_SAMPLES];\n"
105
106     "void main()\n"
107     "{\n"
108     "   mediump vec4 col = texture2D(sTexture, vTexCoord + uSampleOffsets[0]) * uSampleWeights[0];\n"
109     "   for (int i=1; i<NUM_SAMPLES; ++i)\n"
110     "   {\n"
111     "     col += texture2D(sTexture, vTexCoord + uSampleOffsets[i]) * uSampleWeights[i];\n"
112     "   }\n"
113     "   gl_FragColor = col;\n"
114     "}\n";
115
116 } // namespace
117
118
119 GaussianBlurView::GaussianBlurView()
120 : Control( ControlBehaviour( DISABLE_SIZE_NEGOTIATION | DISABLE_STYLE_CHANGE_SIGNALS ) ),
121   mNumSamples(GAUSSIAN_BLUR_VIEW_DEFAULT_NUM_SAMPLES),
122   mBlurBellCurveWidth( 0.001f ),
123   mPixelFormat(GAUSSIAN_BLUR_VIEW_DEFAULT_RENDER_TARGET_PIXEL_FORMAT),
124   mDownsampleWidthScale(GAUSSIAN_BLUR_VIEW_DEFAULT_DOWNSAMPLE_WIDTH_SCALE),
125   mDownsampleHeightScale(GAUSSIAN_BLUR_VIEW_DEFAULT_DOWNSAMPLE_HEIGHT_SCALE),
126   mDownsampledWidth( 0.0f ),
127   mDownsampledHeight( 0.0f ),
128   mBlurUserImage( false ),
129   mRenderOnce( false ),
130   mBackgroundColor( Color::BLACK ),
131   mTargetSize(Vector2::ZERO),
132   mLastSize(Vector2::ZERO),
133   mChildrenRoot(Actor::New()),
134   mInternalRoot(Actor::New()),
135   mBlurStrengthPropertyIndex(Property::INVALID_INDEX),
136   mActivated( false )
137 {
138   SetBlurBellCurveWidth(GAUSSIAN_BLUR_VIEW_DEFAULT_BLUR_BELL_CURVE_WIDTH);
139 }
140
141 GaussianBlurView::GaussianBlurView( const unsigned int numSamples,
142                                     const float blurBellCurveWidth,
143                                     const Pixel::Format renderTargetPixelFormat,
144                                     const float downsampleWidthScale,
145                                     const float downsampleHeightScale,
146                                     bool blurUserImage)
147 : Control( ControlBehaviour( DISABLE_SIZE_NEGOTIATION | DISABLE_STYLE_CHANGE_SIGNALS ) ),
148   mNumSamples(numSamples),
149   mBlurBellCurveWidth( 0.001f ),
150   mPixelFormat(renderTargetPixelFormat),
151   mDownsampleWidthScale(downsampleWidthScale),
152   mDownsampleHeightScale(downsampleHeightScale),
153   mDownsampledWidth( 0.0f ),
154   mDownsampledHeight( 0.0f ),
155   mBlurUserImage( blurUserImage ),
156   mRenderOnce( false ),
157   mBackgroundColor( Color::BLACK ),
158   mTargetSize(Vector2::ZERO),
159   mLastSize(Vector2::ZERO),
160   mChildrenRoot(Actor::New()),
161   mInternalRoot(Actor::New()),
162   mBlurStrengthPropertyIndex(Property::INVALID_INDEX),
163   mActivated( false )
164 {
165   SetBlurBellCurveWidth(blurBellCurveWidth);
166 }
167
168 GaussianBlurView::~GaussianBlurView()
169 {
170 }
171
172
173 Toolkit::GaussianBlurView GaussianBlurView::New()
174 {
175   GaussianBlurView* impl = new GaussianBlurView();
176
177   Dali::Toolkit::GaussianBlurView handle = Dali::Toolkit::GaussianBlurView( *impl );
178
179   // Second-phase init of the implementation
180   // This can only be done after the CustomActor connection has been made...
181   impl->Initialize();
182
183   return handle;
184 }
185
186 Toolkit::GaussianBlurView GaussianBlurView::New(const unsigned int numSamples, const float blurBellCurveWidth, const Pixel::Format renderTargetPixelFormat,
187                                                 const float downsampleWidthScale, const float downsampleHeightScale,
188                                                 bool blurUserImage)
189 {
190   GaussianBlurView* impl = new GaussianBlurView( numSamples, blurBellCurveWidth, renderTargetPixelFormat,
191                                                  downsampleWidthScale, downsampleHeightScale,
192                                                  blurUserImage);
193
194   Dali::Toolkit::GaussianBlurView handle = Dali::Toolkit::GaussianBlurView( *impl );
195
196   // Second-phase init of the implementation
197   // This can only be done after the CustomActor connection has been made...
198   impl->Initialize();
199
200   return handle;
201 }
202
203 /////////////////////////////////////////////////////////////
204 // for creating a subtree for all user added child actors, so that we can have them exclusive to the mRenderChildrenTask and our other actors exclusive to our other tasks
205 // DEPRECATED: overloading Actor::Add()/Remove() not nice since breaks polymorphism. Need another method to pass ownership of added child actors to our internal actor root.
206 void GaussianBlurView::Add(Actor child)
207 {
208   mChildrenRoot.Add(child);
209 }
210
211 void GaussianBlurView::Remove(Actor child)
212 {
213   mChildrenRoot.Remove(child);
214 }
215
216 void GaussianBlurView::SetUserImageAndOutputRenderTarget(Image inputImage, FrameBufferImage outputRenderTarget)
217 {
218   // can only do this if the GaussianBlurView object was created with this parameter set
219   DALI_ASSERT_ALWAYS(mBlurUserImage);
220
221   mUserInputImage = inputImage;
222   mImageViewHorizBlur.SetImage( mUserInputImage );
223   mImageViewHorizBlur.SetProperty( Toolkit::ImageView::Property::IMAGE, mCustomShader );
224
225   mUserOutputRenderTarget = outputRenderTarget;
226 }
227
228 FrameBufferImage GaussianBlurView::GetBlurredRenderTarget() const
229 {
230   if(!mUserOutputRenderTarget)
231   {
232     return mRenderTargetForRenderingChildren;
233   }
234
235   return mUserOutputRenderTarget;
236 }
237
238 void GaussianBlurView::SetBackgroundColor( const Vector4& color )
239 {
240   mBackgroundColor = color;
241 }
242
243 Vector4 GaussianBlurView::GetBackgroundColor() const
244 {
245   return mBackgroundColor;
246 }
247
248 ///////////////////////////////////////////////////////////
249 //
250 // Private methods
251 //
252
253 void GaussianBlurView::OnInitialize()
254 {
255   // root actor to parent all user added actors, needed to allow us to set that subtree as exclusive for our child render task
256   mChildrenRoot.SetParentOrigin(ParentOrigin::CENTER);
257   mInternalRoot.SetParentOrigin(ParentOrigin::CENTER);
258
259   //////////////////////////////////////////////////////
260   // Create shaders
261
262   std::ostringstream horizFragmentShaderStringStream;
263   horizFragmentShaderStringStream << "#define NUM_SAMPLES " << mNumSamples << "\n";
264   horizFragmentShaderStringStream << GAUSSIAN_BLUR_FRAGMENT_SOURCE;
265   Property::Map source;
266   source[ Toolkit::Visual::Shader::Property::FRAGMENT_SHADER ] = horizFragmentShaderStringStream.str();
267   mCustomShader[ Toolkit::VisualProperty::SHADER ] = source;
268
269   //////////////////////////////////////////////////////
270   // Create actors
271
272   // Create an image view for performing a horizontal blur on the texture
273   mImageViewHorizBlur = Toolkit::ImageView::New();
274   mImageViewHorizBlur.SetParentOrigin(ParentOrigin::CENTER);
275
276   // Create an image view for performing a vertical blur on the texture
277   mImageViewVertBlur = Toolkit::ImageView::New();
278   mImageViewVertBlur.SetParentOrigin(ParentOrigin::CENTER);
279
280   // Register a property that the user can control to fade the blur in / out via the GaussianBlurView object
281   Actor self = Self();
282   mBlurStrengthPropertyIndex = self.RegisterProperty(GAUSSIAN_BLUR_VIEW_STRENGTH_PROPERTY_NAME, GAUSSIAN_BLUR_VIEW_DEFAULT_BLUR_STRENGTH);
283
284   // Create an image view for compositing the blur and the original child actors render
285   if(!mBlurUserImage)
286   {
287     mImageViewComposite = Toolkit::ImageView::New();
288     mImageViewComposite.SetParentOrigin(ParentOrigin::CENTER);
289     mImageViewComposite.SetOpacity(GAUSSIAN_BLUR_VIEW_DEFAULT_BLUR_STRENGTH); // ensure alpha is enabled for this object and set default value
290
291     Constraint blurStrengthConstraint = Constraint::New<float>( mImageViewComposite, Actor::Property::COLOR_ALPHA, EqualToConstraint());
292     blurStrengthConstraint.AddSource( Source( self, mBlurStrengthPropertyIndex) );
293     blurStrengthConstraint.Apply();
294
295     // Create an image view for holding final result, i.e. the blurred image. This will get rendered to screen later, via default / user render task
296     mTargetActor = Toolkit::ImageView::New();
297     mTargetActor.SetParentOrigin(ParentOrigin::CENTER);
298
299     //////////////////////////////////////////////////////
300     // Create cameras for the renders corresponding to the view size
301     mRenderFullSizeCamera = CameraActor::New();
302     mRenderFullSizeCamera.SetInvertYAxis( true );
303     mRenderFullSizeCamera.SetParentOrigin(ParentOrigin::CENTER);
304
305
306     //////////////////////////////////////////////////////
307     // Connect to actor tree
308     mInternalRoot.Add( mImageViewComposite );
309     mInternalRoot.Add( mTargetActor );
310     mInternalRoot.Add( mRenderFullSizeCamera );
311   }
312
313
314   //////////////////////////////////////////////////////
315   // Create camera for the renders corresponding to the (potentially downsampled) render targets' size
316   mRenderDownsampledCamera = CameraActor::New();
317   mRenderDownsampledCamera.SetInvertYAxis( true );
318   mRenderDownsampledCamera.SetParentOrigin(ParentOrigin::CENTER);
319
320
321   //////////////////////////////////////////////////////
322   // Connect to actor tree
323   Self().Add( mChildrenRoot );
324   Self().Add( mInternalRoot );
325   mInternalRoot.Add( mImageViewHorizBlur );
326   mInternalRoot.Add( mImageViewVertBlur );
327   mInternalRoot.Add( mRenderDownsampledCamera );
328 }
329
330
331 void GaussianBlurView::OnSizeSet(const Vector3& targetSize)
332 {
333   Control::OnSizeSet( targetSize );
334
335   mTargetSize = Vector2(targetSize);
336
337   mChildrenRoot.SetSize(targetSize);
338
339   if( !mBlurUserImage )
340   {
341     mImageViewComposite.SetSize(targetSize);
342     mTargetActor.SetSize(targetSize);
343
344     // Children render camera must move when GaussianBlurView object is resized. This is since we cannot change render target size - so we need to remap the child actors' rendering
345     // accordingly so they still exactly fill the render target. Note that this means the effective resolution of the child render changes as the GaussianBlurView object changes
346     // size, this is the trade off for not being able to modify render target size
347     // Change camera z position based on GaussianBlurView actor height
348     float cameraPosConstraintScale = 0.5f / tanf(ARBITRARY_FIELD_OF_VIEW * 0.5f);
349     mRenderFullSizeCamera.SetZ(mTargetSize.height * cameraPosConstraintScale);
350   }
351
352
353   // if we have already activated the blur, need to update render target sizes now to reflect the new size of this actor
354   if(mActivated)
355   {
356     Deactivate();
357     Activate();
358   }
359 }
360
361 void GaussianBlurView::OnChildAdd( Actor& child )
362 {
363   Control::OnChildAdd( child );
364
365   if( child != mChildrenRoot && child != mInternalRoot)
366   {
367     mChildrenRoot.Add( child );
368   }
369 }
370
371 void GaussianBlurView::OnChildRemove( Actor& child )
372 {
373   mChildrenRoot.Remove( child );
374
375   Control::OnChildRemove( child );
376 }
377
378 void GaussianBlurView::AllocateResources()
379 {
380   // size of render targets etc is based on the size of this actor, ignoring z
381   if(mTargetSize != mLastSize)
382   {
383     mLastSize = mTargetSize;
384
385     // get size of downsampled render targets
386     mDownsampledWidth = mTargetSize.width * mDownsampleWidthScale;
387     mDownsampledHeight = mTargetSize.height * mDownsampleHeightScale;
388
389     // Create and place a camera for the renders corresponding to the (potentially downsampled) render targets' size
390     mRenderDownsampledCamera.SetFieldOfView(ARBITRARY_FIELD_OF_VIEW);
391     // TODO: how do we pick a reasonable value for near clip? Needs to relate to normal camera the user renders with, but we don't have a handle on it
392     mRenderDownsampledCamera.SetNearClippingPlane(1.0f);
393     mRenderDownsampledCamera.SetAspectRatio(mDownsampledWidth / mDownsampledHeight);
394     mRenderDownsampledCamera.SetType(Dali::Camera::FREE_LOOK); // camera orientation based solely on actor
395
396     mRenderDownsampledCamera.SetPosition(0.0f, 0.0f, ((mDownsampledHeight * 0.5f) / tanf(ARBITRARY_FIELD_OF_VIEW * 0.5f)));
397
398     // setup for normal operation
399     if(!mBlurUserImage)
400     {
401       // Create and place a camera for the children render, corresponding to its render target size
402       mRenderFullSizeCamera.SetFieldOfView(ARBITRARY_FIELD_OF_VIEW);
403       // TODO: how do we pick a reasonable value for near clip? Needs to relate to normal camera the user renders with, but we don't have a handle on it
404       mRenderFullSizeCamera.SetNearClippingPlane(1.0f);
405       mRenderFullSizeCamera.SetAspectRatio(mTargetSize.width / mTargetSize.height);
406       mRenderFullSizeCamera.SetType(Dali::Camera::FREE_LOOK); // camera orientation based solely on actor
407
408       float cameraPosConstraintScale = 0.5f / tanf(ARBITRARY_FIELD_OF_VIEW * 0.5f);
409       mRenderFullSizeCamera.SetPosition(0.0f, 0.0f, mTargetSize.height * cameraPosConstraintScale);
410
411       // create offscreen buffer of new size to render our child actors to
412       mRenderTargetForRenderingChildren = FrameBufferImage::New( mTargetSize.width, mTargetSize.height, mPixelFormat );
413
414       // Set image view for performing a horizontal blur on the texture
415       mImageViewHorizBlur.SetImage( mRenderTargetForRenderingChildren );
416       mImageViewHorizBlur.SetProperty( Toolkit::ImageView::Property::IMAGE, mCustomShader );
417
418       // Create offscreen buffer for vert blur pass
419       mRenderTarget1 = FrameBufferImage::New( mDownsampledWidth, mDownsampledHeight, mPixelFormat );
420
421       // use the completed blur in the first buffer and composite with the original child actors render
422       mImageViewComposite.SetImage( mRenderTarget1 );
423
424       // set up target actor for rendering result, i.e. the blurred image
425       mTargetActor.SetImage(mRenderTargetForRenderingChildren);
426     }
427
428     // Create offscreen buffer for horiz blur pass
429     mRenderTarget2 = FrameBufferImage::New( mDownsampledWidth, mDownsampledHeight, mPixelFormat );
430
431     // size needs to match render target
432     mImageViewHorizBlur.SetSize(mDownsampledWidth, mDownsampledHeight);
433
434     // size needs to match render target
435     mImageViewVertBlur.SetImage( mRenderTarget2 );
436     mImageViewVertBlur.SetProperty( Toolkit::ImageView::Property::IMAGE, mCustomShader );
437     mImageViewVertBlur.SetSize(mDownsampledWidth, mDownsampledHeight);
438
439     // set gaussian blur up for new sized render targets
440     SetShaderConstants();
441   }
442 }
443
444 void GaussianBlurView::CreateRenderTasks()
445 {
446   RenderTaskList taskList = Stage::GetCurrent().GetRenderTaskList();
447
448   if(!mBlurUserImage)
449   {
450     // create render task to render our child actors to offscreen buffer
451     mRenderChildrenTask = taskList.CreateTask();
452     mRenderChildrenTask.SetSourceActor( mChildrenRoot );
453     mRenderChildrenTask.SetExclusive(true);
454     mRenderChildrenTask.SetInputEnabled( false );
455     mRenderChildrenTask.SetClearEnabled( true );
456     mRenderChildrenTask.SetClearColor( mBackgroundColor );
457
458     mRenderChildrenTask.SetCameraActor(mRenderFullSizeCamera);
459     mRenderChildrenTask.SetTargetFrameBuffer( mRenderTargetForRenderingChildren );
460   }
461
462   // perform a horizontal blur targeting the second buffer
463   mHorizBlurTask = taskList.CreateTask();
464   mHorizBlurTask.SetSourceActor( mImageViewHorizBlur );
465   mHorizBlurTask.SetExclusive(true);
466   mHorizBlurTask.SetInputEnabled( false );
467   mHorizBlurTask.SetClearEnabled( true );
468   mHorizBlurTask.SetClearColor( mBackgroundColor );
469   mHorizBlurTask.SetCameraActor(mRenderDownsampledCamera);
470   mHorizBlurTask.SetTargetFrameBuffer( mRenderTarget2 );
471   if( mRenderOnce && mBlurUserImage )
472   {
473     mHorizBlurTask.SetRefreshRate(RenderTask::REFRESH_ONCE);
474   }
475
476   // use the second buffer and perform a horizontal blur targeting the first buffer
477   mVertBlurTask = taskList.CreateTask();
478   mVertBlurTask.SetSourceActor( mImageViewVertBlur );
479   mVertBlurTask.SetExclusive(true);
480   mVertBlurTask.SetInputEnabled( false );
481   mVertBlurTask.SetClearEnabled( true );
482   mVertBlurTask.SetClearColor( mBackgroundColor );
483   mVertBlurTask.SetCameraActor(mRenderDownsampledCamera);
484   if(mUserOutputRenderTarget)
485   {
486     mVertBlurTask.SetTargetFrameBuffer( mUserOutputRenderTarget );
487   }
488   else
489   {
490     mVertBlurTask.SetTargetFrameBuffer( mRenderTarget1 );
491   }
492   if( mRenderOnce && mBlurUserImage )
493   {
494     mVertBlurTask.SetRefreshRate(RenderTask::REFRESH_ONCE);
495     mVertBlurTask.FinishedSignal().Connect( this, &GaussianBlurView::OnRenderTaskFinished );
496   }
497
498   // use the completed blur in the first buffer and composite with the original child actors render
499   if(!mBlurUserImage)
500   {
501     mCompositeTask = taskList.CreateTask();
502     mCompositeTask.SetSourceActor( mImageViewComposite );
503     mCompositeTask.SetExclusive(true);
504     mCompositeTask.SetInputEnabled( false );
505
506     mCompositeTask.SetCameraActor(mRenderFullSizeCamera);
507     mCompositeTask.SetTargetFrameBuffer( mRenderTargetForRenderingChildren );
508   }
509 }
510
511 void GaussianBlurView::RemoveRenderTasks()
512 {
513   RenderTaskList taskList = Stage::GetCurrent().GetRenderTaskList();
514
515   taskList.RemoveTask(mRenderChildrenTask);
516   taskList.RemoveTask(mHorizBlurTask);
517   taskList.RemoveTask(mVertBlurTask);
518   taskList.RemoveTask(mCompositeTask);
519 }
520
521 void GaussianBlurView::Activate()
522 {
523   // make sure resources are allocated and start the render tasks processing
524   AllocateResources();
525   CreateRenderTasks();
526   mActivated = true;
527 }
528
529 void GaussianBlurView::ActivateOnce()
530 {
531   DALI_ASSERT_ALWAYS(mBlurUserImage); // Only works with blurring image mode.
532   mRenderOnce = true;
533   Activate();
534 }
535
536 void GaussianBlurView::Deactivate()
537 {
538   // stop render tasks processing
539   // Note: render target resources are automatically freed since we set the Image::Unused flag
540   RemoveRenderTasks();
541   mRenderTargetForRenderingChildren.Reset();
542   mRenderTarget1.Reset();
543   mRenderTarget2.Reset();
544   mRenderOnce = false;
545   mActivated = false;
546 }
547
548 void GaussianBlurView::SetBlurBellCurveWidth(float blurBellCurveWidth)
549 {
550   // a value of zero leads to undefined Gaussian weights, do not allow user to do this
551   mBlurBellCurveWidth = std::max( blurBellCurveWidth, 0.001f );
552 }
553
554 float GaussianBlurView::CalcGaussianWeight(float x)
555 {
556   return (1.0f / sqrt(2.0f * Math::PI * mBlurBellCurveWidth)) * exp(-(x * x) / (2.0f * mBlurBellCurveWidth * mBlurBellCurveWidth));
557 }
558
559 void GaussianBlurView::SetShaderConstants()
560 {
561   Vector2 *uvOffsets;
562   float ofs;
563   float *weights;
564   float w, totalWeights;
565   unsigned int i;
566
567   uvOffsets = new Vector2[mNumSamples + 1];
568   weights = new float[mNumSamples + 1];
569
570   totalWeights = weights[0] = CalcGaussianWeight(0);
571   uvOffsets[0].x = 0.0f;
572   uvOffsets[0].y = 0.0f;
573
574   for(i=0; i<mNumSamples >> 1; i++)
575   {
576     w = CalcGaussianWeight((float)(i + 1));
577     weights[(i << 1) + 1] = w;
578     weights[(i << 1) + 2] = w;
579     totalWeights += w * 2.0f;
580
581     // offset texture lookup to between texels, that way the bilinear filter in the texture hardware will average two samples with one lookup
582     ofs = ((float)(i << 1)) + 1.5f;
583
584     // get offsets from units of pixels into uv coordinates in [0..1]
585     float ofsX = ofs / mDownsampledWidth;
586     float ofsY = ofs / mDownsampledHeight;
587     uvOffsets[(i << 1) + 1].x = ofsX;
588     uvOffsets[(i << 1) + 1].y = ofsY;
589
590     uvOffsets[(i << 1) + 2].x = -ofsX;
591     uvOffsets[(i << 1) + 2].y = -ofsY;
592   }
593
594   for(i=0; i<mNumSamples; i++)
595   {
596     weights[i] /= totalWeights;
597   }
598
599   // set shader constants
600   Vector2 xAxis(1.0f, 0.0f);
601   Vector2 yAxis(0.0f, 1.0f);
602   for (i = 0; i < mNumSamples; ++i )
603   {
604     mImageViewHorizBlur.RegisterProperty( GetSampleOffsetsPropertyName( i ), uvOffsets[ i ] * xAxis );
605     mImageViewHorizBlur.RegisterProperty( GetSampleWeightsPropertyName( i ), weights[ i ] );
606
607     mImageViewVertBlur.RegisterProperty( GetSampleOffsetsPropertyName( i ), uvOffsets[ i ] * yAxis );
608     mImageViewVertBlur.RegisterProperty( GetSampleWeightsPropertyName( i ), weights[ i ] );
609   }
610
611   delete[] uvOffsets;
612   delete[] weights;
613 }
614
615 std::string GaussianBlurView::GetSampleOffsetsPropertyName( unsigned int index ) const
616 {
617   DALI_ASSERT_ALWAYS( index < mNumSamples );
618
619   std::ostringstream oss;
620   oss << "uSampleOffsets[" << index << "]";
621   return oss.str();
622 }
623
624 std::string GaussianBlurView::GetSampleWeightsPropertyName( unsigned int index ) const
625 {
626   DALI_ASSERT_ALWAYS( index < mNumSamples );
627
628   std::ostringstream oss;
629   oss << "uSampleWeights[" << index << "]";
630   return oss.str();
631 }
632
633 Dali::Toolkit::GaussianBlurView::GaussianBlurViewSignal& GaussianBlurView::FinishedSignal()
634 {
635   return mFinishedSignal;
636 }
637
638 void GaussianBlurView::OnRenderTaskFinished(Dali::RenderTask& renderTask)
639 {
640   Toolkit::GaussianBlurView handle( GetOwner() );
641   mFinishedSignal.Emit( handle );
642 }
643
644 } // namespace Internal
645 } // namespace Toolkit
646 } // namespace Dali