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