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