Merge "Unparents internalRoot actor when gaussian-blur-view is deactived." into devel...
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / controls / gaussian-blur-view / gaussian-blur-view-impl.cpp
1 /*
2  * Copyright (c) 2017 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 // CLASS HEADER
19 #include "gaussian-blur-view-impl.h"
20
21 // EXTERNAL INCLUDES
22 #include <sstream>
23 #include <iomanip>
24 #include <dali/public-api/animation/constraint.h>
25 #include <dali/public-api/animation/constraints.h>
26 #include <dali/public-api/common/stage.h>
27 #include <dali/public-api/object/type-registry.h>
28 #include <dali/public-api/object/type-registry-helper.h>
29 #include <dali/public-api/rendering/geometry.h>
30 #include <dali/public-api/rendering/property-buffer.h>
31 #include <dali/public-api/rendering/renderer.h>
32 #include <dali/public-api/rendering/shader.h>
33 #include <dali/public-api/render-tasks/render-task-list.h>
34 #include <dali/integration-api/debug.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 /////////////////////////////////////////////////////////////
210 // for creating a subtree for all user added child actors, so that we can have them exclusive to the mRenderChildrenTask and our other actors exclusive to our other tasks
211 // DEPRECATED: overloading Actor::Add()/Remove() not nice since breaks polymorphism. Need another method to pass ownership of added child actors to our internal actor root.
212 void GaussianBlurView::Add(Actor child)
213 {
214   mChildrenRoot.Add(child);
215 }
216
217 void GaussianBlurView::Remove(Actor child)
218 {
219   mChildrenRoot.Remove(child);
220 }
221
222 void GaussianBlurView::SetUserImageAndOutputRenderTarget(Texture inputImage, FrameBuffer outputRenderTarget)
223 {
224   // can only do this if the GaussianBlurView object was created with this parameter set
225   DALI_ASSERT_ALWAYS(mBlurUserImage);
226
227   mUserInputImage = inputImage;
228
229   SetRendererTexture( mHorizBlurActor.GetRendererAt(0), inputImage );
230
231   mUserOutputRenderTarget = outputRenderTarget;
232 }
233
234 FrameBuffer GaussianBlurView::GetBlurredRenderTarget() const
235 {
236   if(!mUserOutputRenderTarget)
237   {
238     return mRenderTargetForRenderingChildren;
239   }
240
241   return mUserOutputRenderTarget;
242 }
243
244 void GaussianBlurView::SetBackgroundColor( const Vector4& color )
245 {
246   mBackgroundColor = color;
247 }
248
249 Vector4 GaussianBlurView::GetBackgroundColor() const
250 {
251   return mBackgroundColor;
252 }
253
254 ///////////////////////////////////////////////////////////
255 //
256 // Private methods
257 //
258
259 void GaussianBlurView::OnInitialize()
260 {
261   // root actor to parent all user added actors, needed to allow us to set that subtree as exclusive for our child render task
262   mChildrenRoot.SetParentOrigin(ParentOrigin::CENTER);
263   mInternalRoot.SetParentOrigin(ParentOrigin::CENTER);
264
265   //////////////////////////////////////////////////////
266   // Create shaders
267
268   std::ostringstream fragmentStringStream;
269   fragmentStringStream << "#define NUM_SAMPLES " << mNumSamples << "\n";
270   fragmentStringStream << GAUSSIAN_BLUR_FRAGMENT_SOURCE;
271   std::string fragmentSource(fragmentStringStream.str());
272
273   //////////////////////////////////////////////////////
274   // Create actors
275
276   // Create an actor for performing a horizontal blur on the texture
277   mHorizBlurActor = Actor::New();
278   mHorizBlurActor.SetParentOrigin(ParentOrigin::CENTER);
279   Renderer renderer = CreateRenderer( BASIC_VERTEX_SOURCE, fragmentSource.c_str() );
280   mHorizBlurActor.AddRenderer( renderer );
281
282   // Create an actor for performing a vertical blur on the texture
283   mVertBlurActor = Actor::New();
284   mVertBlurActor.SetParentOrigin(ParentOrigin::CENTER);
285   renderer = CreateRenderer( BASIC_VERTEX_SOURCE, fragmentSource.c_str() );
286   mVertBlurActor.AddRenderer( renderer );
287
288   // Register a property that the user can control to fade the blur in / out via the GaussianBlurView object
289   Actor self = Self();
290   mBlurStrengthPropertyIndex = self.RegisterProperty(GAUSSIAN_BLUR_VIEW_STRENGTH_PROPERTY_NAME, GAUSSIAN_BLUR_VIEW_DEFAULT_BLUR_STRENGTH);
291
292   // Create an image view for compositing the blur and the original child actors render
293   if(!mBlurUserImage)
294   {
295     mCompositingActor = Actor::New();
296     mCompositingActor.SetParentOrigin(ParentOrigin::CENTER);
297     mCompositingActor.SetOpacity(GAUSSIAN_BLUR_VIEW_DEFAULT_BLUR_STRENGTH); // ensure alpha is enabled for this object and set default value
298     renderer = CreateRenderer( BASIC_VERTEX_SOURCE, BASIC_FRAGMENT_SOURCE );
299     mCompositingActor.AddRenderer( renderer );
300
301     Constraint blurStrengthConstraint = Constraint::New<float>( mCompositingActor, Actor::Property::COLOR_ALPHA, EqualToConstraint());
302     blurStrengthConstraint.AddSource( Source( self, mBlurStrengthPropertyIndex) );
303     blurStrengthConstraint.Apply();
304
305     // 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
306     mTargetActor = Actor::New();
307     mTargetActor.SetParentOrigin(ParentOrigin::CENTER);
308     renderer = CreateRenderer( BASIC_VERTEX_SOURCE, BASIC_FRAGMENT_SOURCE );
309     mTargetActor.AddRenderer( renderer );
310
311     //////////////////////////////////////////////////////
312     // Create cameras for the renders corresponding to the view size
313     mRenderFullSizeCamera = CameraActor::New();
314     mRenderFullSizeCamera.SetInvertYAxis( true );
315     mRenderFullSizeCamera.SetParentOrigin(ParentOrigin::CENTER);
316
317     //////////////////////////////////////////////////////
318     // Connect to actor tree
319     mInternalRoot.Add( mCompositingActor );
320     mInternalRoot.Add( mTargetActor );
321     mInternalRoot.Add( mRenderFullSizeCamera );
322   }
323
324   //////////////////////////////////////////////////////
325   // Create camera for the renders corresponding to the (potentially downsampled) render targets' size
326   mRenderDownsampledCamera = CameraActor::New();
327   mRenderDownsampledCamera.SetInvertYAxis( true );
328   mRenderDownsampledCamera.SetParentOrigin(ParentOrigin::CENTER);
329
330   //////////////////////////////////////////////////////
331   // Connect to actor tree
332   Self().Add( mChildrenRoot );
333   mInternalRoot.Add( mHorizBlurActor );
334   mInternalRoot.Add( mVertBlurActor );
335   mInternalRoot.Add( mRenderDownsampledCamera );
336 }
337
338
339 void GaussianBlurView::OnSizeSet(const Vector3& targetSize)
340 {
341   mTargetSize = Vector2(targetSize);
342
343   mChildrenRoot.SetSize(targetSize);
344
345   if( !mBlurUserImage )
346   {
347     mCompositingActor.SetSize(targetSize);
348     mTargetActor.SetSize(targetSize);
349
350     // 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
351     // 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
352     // size, this is the trade off for not being able to modify render target size
353     // Change camera z position based on GaussianBlurView actor height
354     float cameraPosConstraintScale = 0.5f / tanf(ARBITRARY_FIELD_OF_VIEW * 0.5f);
355     mRenderFullSizeCamera.SetZ(mTargetSize.height * cameraPosConstraintScale);
356   }
357
358
359   // if we have already activated the blur, need to update render target sizes now to reflect the new size of this actor
360   if(mActivated)
361   {
362     Deactivate();
363     Activate();
364   }
365
366   Control::OnSizeSet( targetSize );
367 }
368
369 void GaussianBlurView::OnChildAdd( Actor& child )
370 {
371   if( child != mChildrenRoot && child != mInternalRoot)
372   {
373     mChildrenRoot.Add( child );
374   }
375
376   Control::OnChildAdd( child );
377 }
378
379 void GaussianBlurView::OnChildRemove( Actor& child )
380 {
381   mChildrenRoot.Remove( child );
382
383   Control::OnChildRemove( child );
384 }
385
386 void GaussianBlurView::AllocateResources()
387 {
388   // size of render targets etc is based on the size of this actor, ignoring z
389   if(mTargetSize != mLastSize)
390   {
391     mLastSize = mTargetSize;
392
393     // get size of downsampled render targets
394     mDownsampledWidth = mTargetSize.width * mDownsampleWidthScale;
395     mDownsampledHeight = mTargetSize.height * mDownsampleHeightScale;
396
397     // Create and place a camera for the renders corresponding to the (potentially downsampled) render targets' size
398     mRenderDownsampledCamera.SetFieldOfView(ARBITRARY_FIELD_OF_VIEW);
399     // 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
400     mRenderDownsampledCamera.SetNearClippingPlane(1.0f);
401     mRenderDownsampledCamera.SetAspectRatio(mDownsampledWidth / mDownsampledHeight);
402     mRenderDownsampledCamera.SetType(Dali::Camera::FREE_LOOK); // camera orientation based solely on actor
403
404     mRenderDownsampledCamera.SetPosition(0.0f, 0.0f, ((mDownsampledHeight * 0.5f) / tanf(ARBITRARY_FIELD_OF_VIEW * 0.5f)));
405
406     // setup for normal operation
407     if(!mBlurUserImage)
408     {
409       // Create and place a camera for the children render, corresponding to its render target size
410       mRenderFullSizeCamera.SetFieldOfView(ARBITRARY_FIELD_OF_VIEW);
411       // 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
412       mRenderFullSizeCamera.SetNearClippingPlane(1.0f);
413       mRenderFullSizeCamera.SetAspectRatio(mTargetSize.width / mTargetSize.height);
414       mRenderFullSizeCamera.SetType(Dali::Camera::FREE_LOOK); // camera orientation based solely on actor
415
416       float cameraPosConstraintScale = 0.5f / tanf(ARBITRARY_FIELD_OF_VIEW * 0.5f);
417       mRenderFullSizeCamera.SetPosition(0.0f, 0.0f, mTargetSize.height * cameraPosConstraintScale);
418
419       // create offscreen buffer of new size to render our child actors to
420       mRenderTargetForRenderingChildren = FrameBuffer::New( mTargetSize.width, mTargetSize.height, FrameBuffer::Attachment::NONE );
421       Texture texture = Texture::New( TextureType::TEXTURE_2D, mPixelFormat, unsigned(mTargetSize.width), unsigned(mTargetSize.height) );
422       mRenderTargetForRenderingChildren.AttachColorTexture( texture );
423
424       // Set actor for performing a horizontal blur
425       SetRendererTexture( mHorizBlurActor.GetRendererAt(0), mRenderTargetForRenderingChildren );
426
427       // Create offscreen buffer for vert blur pass
428       mRenderTarget1 = FrameBuffer::New( mDownsampledWidth, mDownsampledHeight, FrameBuffer::Attachment::NONE );
429       texture = Texture::New(TextureType::TEXTURE_2D, mPixelFormat, unsigned(mDownsampledWidth), unsigned(mDownsampledHeight));
430       mRenderTarget1.AttachColorTexture( texture );
431
432       // use the completed blur in the first buffer and composite with the original child actors render
433       SetRendererTexture( mCompositingActor.GetRendererAt(0), mRenderTarget1 );
434
435       // set up target actor for rendering result, i.e. the blurred image
436       SetRendererTexture( mTargetActor.GetRendererAt(0), mRenderTargetForRenderingChildren );
437     }
438
439     // Create offscreen buffer for horiz blur pass
440     mRenderTarget2 = FrameBuffer::New( mDownsampledWidth, mDownsampledHeight, FrameBuffer::Attachment::NONE );
441     Texture texture = Texture::New(TextureType::TEXTURE_2D, mPixelFormat, unsigned(mDownsampledWidth), unsigned(mDownsampledHeight));
442     mRenderTarget2.AttachColorTexture( texture );
443
444     // size needs to match render target
445     mHorizBlurActor.SetSize(mDownsampledWidth, mDownsampledHeight);
446
447     // size needs to match render target
448     mVertBlurActor.SetSize(mDownsampledWidth, mDownsampledHeight);
449     SetRendererTexture( mVertBlurActor.GetRendererAt(0), mRenderTarget2 );
450
451     // set gaussian blur up for new sized render targets
452     SetShaderConstants();
453   }
454 }
455
456 void GaussianBlurView::CreateRenderTasks()
457 {
458   RenderTaskList taskList = Stage::GetCurrent().GetRenderTaskList();
459
460   if(!mBlurUserImage)
461   {
462     // create render task to render our child actors to offscreen buffer
463     mRenderChildrenTask = taskList.CreateTask();
464     mRenderChildrenTask.SetSourceActor( mChildrenRoot );
465     mRenderChildrenTask.SetExclusive(true);
466     mRenderChildrenTask.SetInputEnabled( false );
467     mRenderChildrenTask.SetClearEnabled( true );
468     mRenderChildrenTask.SetClearColor( mBackgroundColor );
469
470     mRenderChildrenTask.SetCameraActor(mRenderFullSizeCamera);
471     mRenderChildrenTask.SetFrameBuffer( mRenderTargetForRenderingChildren );
472   }
473
474   // perform a horizontal blur targeting the second buffer
475   mHorizBlurTask = taskList.CreateTask();
476   mHorizBlurTask.SetSourceActor( mHorizBlurActor );
477   mHorizBlurTask.SetExclusive(true);
478   mHorizBlurTask.SetInputEnabled( false );
479   mHorizBlurTask.SetClearEnabled( true );
480   mHorizBlurTask.SetClearColor( mBackgroundColor );
481   mHorizBlurTask.SetCameraActor(mRenderDownsampledCamera);
482   mHorizBlurTask.SetFrameBuffer( mRenderTarget2 );
483   if( mRenderOnce && mBlurUserImage )
484   {
485     mHorizBlurTask.SetRefreshRate(RenderTask::REFRESH_ONCE);
486   }
487
488   // use the second buffer and perform a horizontal blur targeting the first buffer
489   mVertBlurTask = taskList.CreateTask();
490   mVertBlurTask.SetSourceActor( mVertBlurActor );
491   mVertBlurTask.SetExclusive(true);
492   mVertBlurTask.SetInputEnabled( false );
493   mVertBlurTask.SetClearEnabled( true );
494   mVertBlurTask.SetClearColor( mBackgroundColor );
495   mVertBlurTask.SetCameraActor(mRenderDownsampledCamera);
496   if(mUserOutputRenderTarget)
497   {
498     mVertBlurTask.SetFrameBuffer( mUserOutputRenderTarget );
499   }
500   else
501   {
502     mVertBlurTask.SetFrameBuffer( mRenderTarget1 );
503   }
504   if( mRenderOnce && mBlurUserImage )
505   {
506     mVertBlurTask.SetRefreshRate(RenderTask::REFRESH_ONCE);
507     mVertBlurTask.FinishedSignal().Connect( this, &GaussianBlurView::OnRenderTaskFinished );
508   }
509
510   // use the completed blur in the first buffer and composite with the original child actors render
511   if(!mBlurUserImage)
512   {
513     mCompositeTask = taskList.CreateTask();
514     mCompositeTask.SetSourceActor( mCompositingActor );
515     mCompositeTask.SetExclusive(true);
516     mCompositeTask.SetInputEnabled( false );
517
518     mCompositeTask.SetCameraActor(mRenderFullSizeCamera);
519     mCompositeTask.SetFrameBuffer( mRenderTargetForRenderingChildren );
520   }
521 }
522
523 void GaussianBlurView::RemoveRenderTasks()
524 {
525   RenderTaskList taskList = Stage::GetCurrent().GetRenderTaskList();
526
527   taskList.RemoveTask(mRenderChildrenTask);
528   taskList.RemoveTask(mHorizBlurTask);
529   taskList.RemoveTask(mVertBlurTask);
530   taskList.RemoveTask(mCompositeTask);
531 }
532
533 void GaussianBlurView::Activate()
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 void GaussianBlurView::ActivateOnce()
543 {
544   DALI_ASSERT_ALWAYS(mBlurUserImage); // Only works with blurring image mode.
545   mRenderOnce = true;
546   Activate();
547 }
548
549 void GaussianBlurView::Deactivate()
550 {
551   // stop render tasks processing
552   // Note: render target resources are automatically freed since we set the Image::Unused flag
553   mInternalRoot.Unparent();
554   RemoveRenderTasks();
555   mRenderTargetForRenderingChildren.Reset();
556   mRenderTarget1.Reset();
557   mRenderTarget2.Reset();
558   mRenderOnce = false;
559   mActivated = false;
560 }
561
562 void GaussianBlurView::SetBlurBellCurveWidth(float blurBellCurveWidth)
563 {
564   // a value of zero leads to undefined Gaussian weights, do not allow user to do this
565   mBlurBellCurveWidth = std::max( blurBellCurveWidth, 0.001f );
566 }
567
568 float GaussianBlurView::CalcGaussianWeight(float x)
569 {
570   return (1.0f / sqrt(2.0f * Math::PI * mBlurBellCurveWidth)) * exp(-(x * x) / (2.0f * mBlurBellCurveWidth * mBlurBellCurveWidth));
571 }
572
573 void GaussianBlurView::SetShaderConstants()
574 {
575   Vector2 *uvOffsets;
576   float ofs;
577   float *weights;
578   float w, totalWeights;
579   unsigned int i;
580
581   uvOffsets = new Vector2[mNumSamples + 1];
582   weights = new float[mNumSamples + 1];
583
584   totalWeights = weights[0] = CalcGaussianWeight(0);
585   uvOffsets[0].x = 0.0f;
586   uvOffsets[0].y = 0.0f;
587
588   for(i=0; i<mNumSamples >> 1; i++)
589   {
590     w = CalcGaussianWeight((float)(i + 1));
591     weights[(i << 1) + 1] = w;
592     weights[(i << 1) + 2] = w;
593     totalWeights += w * 2.0f;
594
595     // offset texture lookup to between texels, that way the bilinear filter in the texture hardware will average two samples with one lookup
596     ofs = ((float)(i << 1)) + 1.5f;
597
598     // get offsets from units of pixels into uv coordinates in [0..1]
599     float ofsX = ofs / mDownsampledWidth;
600     float ofsY = ofs / mDownsampledHeight;
601     uvOffsets[(i << 1) + 1].x = ofsX;
602     uvOffsets[(i << 1) + 1].y = ofsY;
603
604     uvOffsets[(i << 1) + 2].x = -ofsX;
605     uvOffsets[(i << 1) + 2].y = -ofsY;
606   }
607
608   for(i=0; i<mNumSamples; i++)
609   {
610     weights[i] /= totalWeights;
611   }
612
613   // set shader constants
614   Vector2 xAxis(1.0f, 0.0f);
615   Vector2 yAxis(0.0f, 1.0f);
616   for (i = 0; i < mNumSamples; ++i )
617   {
618     mHorizBlurActor.RegisterProperty( GetSampleOffsetsPropertyName( i ), uvOffsets[ i ] * xAxis );
619     mHorizBlurActor.RegisterProperty( GetSampleWeightsPropertyName( i ), weights[ i ] );
620
621     mVertBlurActor.RegisterProperty( GetSampleOffsetsPropertyName( i ), uvOffsets[ i ] * yAxis );
622     mVertBlurActor.RegisterProperty( GetSampleWeightsPropertyName( i ), weights[ i ] );
623   }
624
625   delete[] uvOffsets;
626   delete[] weights;
627 }
628
629 std::string GaussianBlurView::GetSampleOffsetsPropertyName( unsigned int index ) const
630 {
631   DALI_ASSERT_ALWAYS( index < mNumSamples );
632
633   std::ostringstream oss;
634   oss << "uSampleOffsets[" << index << "]";
635   return oss.str();
636 }
637
638 std::string GaussianBlurView::GetSampleWeightsPropertyName( unsigned int index ) const
639 {
640   DALI_ASSERT_ALWAYS( index < mNumSamples );
641
642   std::ostringstream oss;
643   oss << "uSampleWeights[" << index << "]";
644   return oss.str();
645 }
646
647 Dali::Toolkit::GaussianBlurView::GaussianBlurViewSignal& GaussianBlurView::FinishedSignal()
648 {
649   return mFinishedSignal;
650 }
651
652 void GaussianBlurView::OnRenderTaskFinished(Dali::RenderTask& renderTask)
653 {
654   Toolkit::GaussianBlurView handle( GetOwner() );
655   mFinishedSignal.Emit( handle );
656 }
657
658 } // namespace Internal
659 } // namespace Toolkit
660 } // namespace Dali