[AT-SPI] Fix role setting
[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 }
147
148 GaussianBlurView::GaussianBlurView( const unsigned int numSamples,
149                                     const float blurBellCurveWidth,
150                                     const Pixel::Format renderTargetPixelFormat,
151                                     const float downsampleWidthScale,
152                                     const float downsampleHeightScale,
153                                     bool blurUserImage)
154 : Control( ControlBehaviour( DISABLE_SIZE_NEGOTIATION | DISABLE_STYLE_CHANGE_SIGNALS ) ),
155   mNumSamples(numSamples),
156   mBlurBellCurveWidth( 0.001f ),
157   mPixelFormat(renderTargetPixelFormat),
158   mDownsampleWidthScale(downsampleWidthScale),
159   mDownsampleHeightScale(downsampleHeightScale),
160   mDownsampledWidth( 0.0f ),
161   mDownsampledHeight( 0.0f ),
162   mBlurUserImage( blurUserImage ),
163   mRenderOnce( false ),
164   mBackgroundColor( Color::BLACK ),
165   mTargetSize(Vector2::ZERO),
166   mLastSize(Vector2::ZERO),
167   mChildrenRoot(Actor::New()),
168   mInternalRoot(Actor::New()),
169   mBlurStrengthPropertyIndex(Property::INVALID_INDEX),
170   mActivated( false )
171 {
172   SetBlurBellCurveWidth(blurBellCurveWidth);
173 }
174
175 GaussianBlurView::~GaussianBlurView()
176 {
177 }
178
179
180 Toolkit::GaussianBlurView GaussianBlurView::New()
181 {
182   GaussianBlurView* impl = new GaussianBlurView();
183
184   Dali::Toolkit::GaussianBlurView handle = Dali::Toolkit::GaussianBlurView( *impl );
185
186   // Second-phase init of the implementation
187   // This can only be done after the CustomActor connection has been made...
188   impl->Initialize();
189
190   return handle;
191 }
192
193 Toolkit::GaussianBlurView GaussianBlurView::New(const unsigned int numSamples, const float blurBellCurveWidth, const Pixel::Format renderTargetPixelFormat,
194                                                 const float downsampleWidthScale, const float downsampleHeightScale,
195                                                 bool blurUserImage)
196 {
197   GaussianBlurView* impl = new GaussianBlurView( numSamples, blurBellCurveWidth, renderTargetPixelFormat,
198                                                  downsampleWidthScale, downsampleHeightScale,
199                                                  blurUserImage);
200
201   Dali::Toolkit::GaussianBlurView handle = Dali::Toolkit::GaussianBlurView( *impl );
202
203   // Second-phase init of the implementation
204   // This can only be done after the CustomActor connection has been made...
205   impl->Initialize();
206
207   return handle;
208 }
209
210 void GaussianBlurView::SetUserImageAndOutputRenderTarget(Texture inputImage, FrameBuffer outputRenderTarget)
211 {
212   // can only do this if the GaussianBlurView object was created with this parameter set
213   DALI_ASSERT_ALWAYS(mBlurUserImage);
214
215   mUserInputImage = inputImage;
216
217   SetRendererTexture( mHorizBlurActor.GetRendererAt(0), inputImage );
218
219   mUserOutputRenderTarget = outputRenderTarget;
220 }
221
222 FrameBuffer GaussianBlurView::GetBlurredRenderTarget() const
223 {
224   if(!mUserOutputRenderTarget)
225   {
226     return mRenderTargetForRenderingChildren;
227   }
228
229   return mUserOutputRenderTarget;
230 }
231
232 void GaussianBlurView::SetBackgroundColor( const Vector4& color )
233 {
234   mBackgroundColor = color;
235 }
236
237 Vector4 GaussianBlurView::GetBackgroundColor() const
238 {
239   return mBackgroundColor;
240 }
241
242 ///////////////////////////////////////////////////////////
243 //
244 // Private methods
245 //
246
247 void GaussianBlurView::OnInitialize()
248 {
249   // root actor to parent all user added actors, needed to allow us to set that subtree as exclusive for our child render task
250   mChildrenRoot.SetProperty( Actor::Property::PARENT_ORIGIN,ParentOrigin::CENTER );
251   mInternalRoot.SetProperty( Actor::Property::PARENT_ORIGIN,ParentOrigin::CENTER );
252
253   //////////////////////////////////////////////////////
254   // Create shaders
255
256   std::ostringstream fragmentStringStream;
257   fragmentStringStream << "#define NUM_SAMPLES " << mNumSamples << "\n";
258   fragmentStringStream << GAUSSIAN_BLUR_FRAGMENT_SOURCE;
259   std::string fragmentSource(fragmentStringStream.str());
260
261   //////////////////////////////////////////////////////
262   // Create actors
263
264   // Create an actor for performing a horizontal blur on the texture
265   mHorizBlurActor = Actor::New();
266   mHorizBlurActor.SetProperty( Actor::Property::PARENT_ORIGIN,ParentOrigin::CENTER );
267   Renderer renderer = CreateRenderer( BASIC_VERTEX_SOURCE, fragmentSource.c_str() );
268   mHorizBlurActor.AddRenderer( renderer );
269
270   // Create an actor for performing a vertical blur on the texture
271   mVertBlurActor = Actor::New();
272   mVertBlurActor.SetProperty( Actor::Property::PARENT_ORIGIN,ParentOrigin::CENTER );
273   renderer = CreateRenderer( BASIC_VERTEX_SOURCE, fragmentSource.c_str() );
274   mVertBlurActor.AddRenderer( renderer );
275
276   // Register a property that the user can control to fade the blur in / out via the GaussianBlurView object
277   Actor self = Self();
278   mBlurStrengthPropertyIndex = self.RegisterProperty(GAUSSIAN_BLUR_VIEW_STRENGTH_PROPERTY_NAME, GAUSSIAN_BLUR_VIEW_DEFAULT_BLUR_STRENGTH);
279
280   // Create an image view for compositing the blur and the original child actors render
281   if(!mBlurUserImage)
282   {
283     mCompositingActor = Actor::New();
284     mCompositingActor.SetProperty( Actor::Property::PARENT_ORIGIN,ParentOrigin::CENTER );
285     mCompositingActor.SetProperty( Actor::Property::OPACITY,GAUSSIAN_BLUR_VIEW_DEFAULT_BLUR_STRENGTH); // ensure alpha is enabled for this object and set default value
286     renderer = CreateRenderer( BASIC_VERTEX_SOURCE, BASIC_FRAGMENT_SOURCE );
287     mCompositingActor.AddRenderer( renderer );
288
289     Constraint blurStrengthConstraint = Constraint::New<float>( mCompositingActor, Actor::Property::COLOR_ALPHA, EqualToConstraint());
290     blurStrengthConstraint.AddSource( Source( self, mBlurStrengthPropertyIndex) );
291     blurStrengthConstraint.Apply();
292
293     // 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
294     mTargetActor = Actor::New();
295     mTargetActor.SetProperty( Actor::Property::PARENT_ORIGIN,ParentOrigin::CENTER );
296     renderer = CreateRenderer( BASIC_VERTEX_SOURCE, BASIC_FRAGMENT_SOURCE );
297     mTargetActor.AddRenderer( renderer );
298
299     //////////////////////////////////////////////////////
300     // Create cameras for the renders corresponding to the view size
301     mRenderFullSizeCamera = CameraActor::New();
302     mRenderFullSizeCamera.SetInvertYAxis( true );
303     mRenderFullSizeCamera.SetProperty( Actor::Property::PARENT_ORIGIN,ParentOrigin::CENTER );
304
305     //////////////////////////////////////////////////////
306     // Connect to actor tree
307     mInternalRoot.Add( mCompositingActor );
308     mInternalRoot.Add( mTargetActor );
309     mInternalRoot.Add( mRenderFullSizeCamera );
310   }
311
312   //////////////////////////////////////////////////////
313   // Create camera for the renders corresponding to the (potentially downsampled) render targets' size
314   mRenderDownsampledCamera = CameraActor::New();
315   mRenderDownsampledCamera.SetInvertYAxis( true );
316   mRenderDownsampledCamera.SetProperty( Actor::Property::PARENT_ORIGIN,ParentOrigin::CENTER );
317
318   //////////////////////////////////////////////////////
319   // Connect to actor tree
320   Self().Add( mChildrenRoot );
321   mInternalRoot.Add( mHorizBlurActor );
322   mInternalRoot.Add( mVertBlurActor );
323   mInternalRoot.Add( mRenderDownsampledCamera );
324
325   DevelControl::SetAccessibilityConstructor( Self(), []( Dali::Actor actor ) {
326     return std::unique_ptr< Dali::Accessibility::Accessible >(
327       new Control::Impl::AccessibleImpl( actor, Dali::Accessibility::Role::FILLER ) );
328   } );
329 }
330
331
332 void GaussianBlurView::OnSizeSet(const Vector3& targetSize)
333 {
334   mTargetSize = Vector2(targetSize);
335
336   mChildrenRoot.SetProperty( Actor::Property::SIZE, targetSize);
337
338   if( !mBlurUserImage )
339   {
340     mCompositingActor.SetProperty( Actor::Property::SIZE, targetSize);
341     mTargetActor.SetProperty( Actor::Property::SIZE, targetSize);
342
343     // 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
344     // 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
345     // size, this is the trade off for not being able to modify render target size
346     // Change camera z position based on GaussianBlurView actor height
347     float cameraPosConstraintScale = 0.5f / tanf(ARBITRARY_FIELD_OF_VIEW * 0.5f);
348     mRenderFullSizeCamera.SetProperty( Actor::Property::POSITION_Z, mTargetSize.height * cameraPosConstraintScale);
349   }
350
351
352   // if we have already activated the blur, need to update render target sizes now to reflect the new size of this actor
353   if(mActivated)
354   {
355     Deactivate();
356     Activate();
357   }
358
359   Control::OnSizeSet( targetSize );
360 }
361
362 void GaussianBlurView::OnChildAdd( Actor& child )
363 {
364   if( child != mChildrenRoot && child != mInternalRoot)
365   {
366     mChildrenRoot.Add( child );
367   }
368
369   Control::OnChildAdd( child );
370 }
371
372 void GaussianBlurView::OnChildRemove( Actor& child )
373 {
374   mChildrenRoot.Remove( child );
375
376   Control::OnChildRemove( child );
377 }
378
379 void GaussianBlurView::AllocateResources()
380 {
381   mLastSize = mTargetSize;
382
383   // get size of downsampled render targets
384   mDownsampledWidth = mTargetSize.width * mDownsampleWidthScale;
385   mDownsampledHeight = mTargetSize.height * mDownsampleHeightScale;
386
387   // Create and place a camera for the renders corresponding to the (potentially downsampled) render targets' size
388   mRenderDownsampledCamera.SetFieldOfView(ARBITRARY_FIELD_OF_VIEW);
389   // 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
390   mRenderDownsampledCamera.SetNearClippingPlane(1.0f);
391   mRenderDownsampledCamera.SetAspectRatio(mDownsampledWidth / mDownsampledHeight);
392   mRenderDownsampledCamera.SetType(Dali::Camera::FREE_LOOK); // camera orientation based solely on actor
393
394   mRenderDownsampledCamera.SetProperty( Actor::Property::POSITION, Vector3(0.0f, 0.0f, ((mDownsampledHeight * 0.5f) / tanf(ARBITRARY_FIELD_OF_VIEW * 0.5f))));
395
396   // setup for normal operation
397   if(!mBlurUserImage)
398   {
399     // Create and place a camera for the children render, corresponding to its render target size
400     mRenderFullSizeCamera.SetFieldOfView(ARBITRARY_FIELD_OF_VIEW);
401     // 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
402     mRenderFullSizeCamera.SetNearClippingPlane(1.0f);
403     mRenderFullSizeCamera.SetAspectRatio(mTargetSize.width / mTargetSize.height);
404     mRenderFullSizeCamera.SetType(Dali::Camera::FREE_LOOK); // camera orientation based solely on actor
405
406     float cameraPosConstraintScale = 0.5f / tanf(ARBITRARY_FIELD_OF_VIEW * 0.5f);
407     mRenderFullSizeCamera.SetProperty( Actor::Property::POSITION, Vector3(0.0f, 0.0f, mTargetSize.height * cameraPosConstraintScale));
408
409     // create offscreen buffer of new size to render our child actors to
410     mRenderTargetForRenderingChildren = FrameBuffer::New( mTargetSize.width, mTargetSize.height, FrameBuffer::Attachment::NONE );
411     Texture texture = Texture::New( TextureType::TEXTURE_2D, mPixelFormat, unsigned(mTargetSize.width), unsigned(mTargetSize.height) );
412     mRenderTargetForRenderingChildren.AttachColorTexture( texture );
413
414     // Set actor for performing a horizontal blur
415     SetRendererTexture( mHorizBlurActor.GetRendererAt(0), mRenderTargetForRenderingChildren );
416
417     // Create offscreen buffer for vert blur pass
418     mRenderTarget1 = FrameBuffer::New( mDownsampledWidth, mDownsampledHeight, FrameBuffer::Attachment::NONE );
419     texture = Texture::New(TextureType::TEXTURE_2D, mPixelFormat, unsigned(mDownsampledWidth), unsigned(mDownsampledHeight));
420     mRenderTarget1.AttachColorTexture( texture );
421
422     // use the completed blur in the first buffer and composite with the original child actors render
423     SetRendererTexture( mCompositingActor.GetRendererAt(0), mRenderTarget1 );
424
425     // set up target actor for rendering result, i.e. the blurred image
426     SetRendererTexture( mTargetActor.GetRendererAt(0), mRenderTargetForRenderingChildren );
427   }
428
429   // Create offscreen buffer for horiz blur pass
430   mRenderTarget2 = FrameBuffer::New( mDownsampledWidth, mDownsampledHeight, FrameBuffer::Attachment::NONE );
431   Texture texture = Texture::New(TextureType::TEXTURE_2D, mPixelFormat, unsigned(mDownsampledWidth), unsigned(mDownsampledHeight));
432   mRenderTarget2.AttachColorTexture( texture );
433
434   // size needs to match render target
435   mHorizBlurActor.SetProperty( Actor::Property::SIZE, Vector2(mDownsampledWidth, mDownsampledHeight) );
436
437   // size needs to match render target
438   mVertBlurActor.SetProperty( Actor::Property::SIZE, Vector2(mDownsampledWidth, mDownsampledHeight) );
439   SetRendererTexture( mVertBlurActor.GetRendererAt(0), mRenderTarget2 );
440
441   // set gaussian blur up for new sized render targets
442   SetShaderConstants();
443 }
444
445 void GaussianBlurView::CreateRenderTasks()
446 {
447   RenderTaskList taskList = Stage::GetCurrent().GetRenderTaskList();
448
449   if(!mBlurUserImage)
450   {
451     // create render task to render our child actors to offscreen buffer
452     mRenderChildrenTask = taskList.CreateTask();
453     mRenderChildrenTask.SetSourceActor( mChildrenRoot );
454     mRenderChildrenTask.SetExclusive(true);
455     mRenderChildrenTask.SetInputEnabled( false );
456     mRenderChildrenTask.SetClearEnabled( true );
457     mRenderChildrenTask.SetClearColor( mBackgroundColor );
458
459     mRenderChildrenTask.SetCameraActor(mRenderFullSizeCamera);
460     mRenderChildrenTask.SetFrameBuffer( mRenderTargetForRenderingChildren );
461
462     if( mRenderOnce )
463     {
464       mRenderChildrenTask.SetRefreshRate(RenderTask::REFRESH_ONCE);
465     }
466   }
467
468   // perform a horizontal blur targeting the second buffer
469   mHorizBlurTask = taskList.CreateTask();
470   mHorizBlurTask.SetSourceActor( mHorizBlurActor );
471   mHorizBlurTask.SetExclusive(true);
472   mHorizBlurTask.SetInputEnabled( false );
473   mHorizBlurTask.SetClearEnabled( true );
474   mHorizBlurTask.SetClearColor( mBackgroundColor );
475   mHorizBlurTask.SetCameraActor(mRenderDownsampledCamera);
476   mHorizBlurTask.SetFrameBuffer( mRenderTarget2 );
477   if( mRenderOnce || ( mRenderOnce && mBlurUserImage ) )
478   {
479     mHorizBlurTask.SetRefreshRate(RenderTask::REFRESH_ONCE);
480   }
481
482   // use the second buffer and perform a horizontal blur targeting the first buffer
483   mVertBlurTask = taskList.CreateTask();
484   mVertBlurTask.SetSourceActor( mVertBlurActor );
485   mVertBlurTask.SetExclusive(true);
486   mVertBlurTask.SetInputEnabled( false );
487   mVertBlurTask.SetClearEnabled( true );
488   mVertBlurTask.SetClearColor( mBackgroundColor );
489   mVertBlurTask.SetCameraActor(mRenderDownsampledCamera);
490   if(mUserOutputRenderTarget)
491   {
492     mVertBlurTask.SetFrameBuffer( mUserOutputRenderTarget );
493   }
494   else
495   {
496     mVertBlurTask.SetFrameBuffer( mRenderTarget1 );
497   }
498   if( mRenderOnce || ( mRenderOnce && mBlurUserImage ) )
499   {
500     mVertBlurTask.SetRefreshRate(RenderTask::REFRESH_ONCE);
501     mVertBlurTask.FinishedSignal().Connect( this, &GaussianBlurView::OnRenderTaskFinished );
502   }
503
504   // use the completed blur in the first buffer and composite with the original child actors render
505   if(!mBlurUserImage)
506   {
507     mCompositeTask = taskList.CreateTask();
508     mCompositeTask.SetSourceActor( mCompositingActor );
509     mCompositeTask.SetExclusive(true);
510     mCompositeTask.SetInputEnabled( false );
511
512     mCompositeTask.SetCameraActor(mRenderFullSizeCamera);
513     mCompositeTask.SetFrameBuffer( mRenderTargetForRenderingChildren );
514
515     if( mRenderOnce )
516     {
517       mCompositeTask.SetRefreshRate(RenderTask::REFRESH_ONCE);
518     }
519   }
520 }
521
522 void GaussianBlurView::RemoveRenderTasks()
523 {
524   RenderTaskList taskList = Stage::GetCurrent().GetRenderTaskList();
525
526   taskList.RemoveTask(mRenderChildrenTask);
527   taskList.RemoveTask(mHorizBlurTask);
528   taskList.RemoveTask(mVertBlurTask);
529   taskList.RemoveTask(mCompositeTask);
530 }
531
532 void GaussianBlurView::Activate()
533 {
534   if( !mActivated )
535   {
536     // make sure resources are allocated and start the render tasks processing
537     Self().Add( mInternalRoot );
538     AllocateResources();
539     CreateRenderTasks();
540     mActivated = true;
541   }
542 }
543
544 void GaussianBlurView::ActivateOnce()
545 {
546   Deactivate();
547   mRenderOnce = true;
548   Activate();
549 }
550
551 void GaussianBlurView::Deactivate()
552 {
553   if( mActivated )
554   {
555     // stop render tasks processing
556     // Note: render target resources are automatically freed since we set the Image::Unused flag
557     mInternalRoot.Unparent();
558     mRenderTargetForRenderingChildren.Reset();
559     mRenderTarget1.Reset();
560     mRenderTarget2.Reset();
561     RemoveRenderTasks();
562     mRenderOnce = false;
563     mActivated = false;
564   }
565 }
566
567 void GaussianBlurView::SetBlurBellCurveWidth(float blurBellCurveWidth)
568 {
569   // a value of zero leads to undefined Gaussian weights, do not allow user to do this
570   mBlurBellCurveWidth = std::max( blurBellCurveWidth, 0.001f );
571 }
572
573 float GaussianBlurView::CalcGaussianWeight(float x)
574 {
575   return (1.0f / sqrt(2.0f * Math::PI * mBlurBellCurveWidth)) * exp(-(x * x) / (2.0f * mBlurBellCurveWidth * mBlurBellCurveWidth));
576 }
577
578 void GaussianBlurView::SetShaderConstants()
579 {
580   Vector2 *uvOffsets;
581   float ofs;
582   float *weights;
583   float w, totalWeights;
584   unsigned int i;
585
586   uvOffsets = new Vector2[mNumSamples + 1];
587   weights = new float[mNumSamples + 1];
588
589   totalWeights = weights[0] = CalcGaussianWeight(0);
590   uvOffsets[0].x = 0.0f;
591   uvOffsets[0].y = 0.0f;
592
593   for(i=0; i<mNumSamples >> 1; i++)
594   {
595     w = CalcGaussianWeight((float)(i + 1));
596     weights[(i << 1) + 1] = w;
597     weights[(i << 1) + 2] = w;
598     totalWeights += w * 2.0f;
599
600     // offset texture lookup to between texels, that way the bilinear filter in the texture hardware will average two samples with one lookup
601     ofs = ((float)(i << 1)) + 1.5f;
602
603     // get offsets from units of pixels into uv coordinates in [0..1]
604     float ofsX = ofs / mDownsampledWidth;
605     float ofsY = ofs / mDownsampledHeight;
606     uvOffsets[(i << 1) + 1].x = ofsX;
607     uvOffsets[(i << 1) + 1].y = ofsY;
608
609     uvOffsets[(i << 1) + 2].x = -ofsX;
610     uvOffsets[(i << 1) + 2].y = -ofsY;
611   }
612
613   for(i=0; i<mNumSamples; i++)
614   {
615     weights[i] /= totalWeights;
616   }
617
618   // set shader constants
619   Vector2 xAxis(1.0f, 0.0f);
620   Vector2 yAxis(0.0f, 1.0f);
621   for (i = 0; i < mNumSamples; ++i )
622   {
623     mHorizBlurActor.RegisterProperty( GetSampleOffsetsPropertyName( i ), uvOffsets[ i ] * xAxis );
624     mHorizBlurActor.RegisterProperty( GetSampleWeightsPropertyName( i ), weights[ i ] );
625
626     mVertBlurActor.RegisterProperty( GetSampleOffsetsPropertyName( i ), uvOffsets[ i ] * yAxis );
627     mVertBlurActor.RegisterProperty( GetSampleWeightsPropertyName( i ), weights[ i ] );
628   }
629
630   delete[] uvOffsets;
631   delete[] weights;
632 }
633
634 std::string GaussianBlurView::GetSampleOffsetsPropertyName( unsigned int index ) const
635 {
636   DALI_ASSERT_ALWAYS( index < mNumSamples );
637
638   std::ostringstream oss;
639   oss << "uSampleOffsets[" << index << "]";
640   return oss.str();
641 }
642
643 std::string GaussianBlurView::GetSampleWeightsPropertyName( unsigned int index ) const
644 {
645   DALI_ASSERT_ALWAYS( index < mNumSamples );
646
647   std::ostringstream oss;
648   oss << "uSampleWeights[" << index << "]";
649   return oss.str();
650 }
651
652 Dali::Toolkit::GaussianBlurView::GaussianBlurViewSignal& GaussianBlurView::FinishedSignal()
653 {
654   return mFinishedSignal;
655 }
656
657 void GaussianBlurView::OnRenderTaskFinished(Dali::RenderTask& renderTask)
658 {
659   Toolkit::GaussianBlurView handle( GetOwner() );
660   mFinishedSignal.Emit( handle );
661 }
662
663 } // namespace Internal
664 } // namespace Toolkit
665 } // namespace Dali