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