Remove non-touch related deprecated APIs
[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/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 #include <dali/devel-api/actors/actor-devel.h>
36
37 // INTERNAL INCLUDES
38 #include <dali-toolkit/public-api/visuals/visual-properties.h>
39 #include <dali-toolkit/internal/controls/control/control-renderers.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
326
327 void GaussianBlurView::OnSizeSet(const Vector3& targetSize)
328 {
329   mTargetSize = Vector2(targetSize);
330
331   mChildrenRoot.SetProperty( Actor::Property::SIZE, targetSize);
332
333   if( !mBlurUserImage )
334   {
335     mCompositingActor.SetProperty( Actor::Property::SIZE, targetSize);
336     mTargetActor.SetProperty( Actor::Property::SIZE, targetSize);
337
338     // 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
339     // 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
340     // size, this is the trade off for not being able to modify render target size
341     // Change camera z position based on GaussianBlurView actor height
342     float cameraPosConstraintScale = 0.5f / tanf(ARBITRARY_FIELD_OF_VIEW * 0.5f);
343     mRenderFullSizeCamera.SetProperty( Actor::Property::POSITION_Z, mTargetSize.height * cameraPosConstraintScale);
344   }
345
346
347   // if we have already activated the blur, need to update render target sizes now to reflect the new size of this actor
348   if(mActivated)
349   {
350     Deactivate();
351     Activate();
352   }
353
354   Control::OnSizeSet( targetSize );
355 }
356
357 void GaussianBlurView::OnChildAdd( Actor& child )
358 {
359   if( child != mChildrenRoot && child != mInternalRoot)
360   {
361     mChildrenRoot.Add( child );
362   }
363
364   Control::OnChildAdd( child );
365 }
366
367 void GaussianBlurView::OnChildRemove( Actor& child )
368 {
369   mChildrenRoot.Remove( child );
370
371   Control::OnChildRemove( child );
372 }
373
374 void GaussianBlurView::AllocateResources()
375 {
376   mLastSize = mTargetSize;
377
378   // get size of downsampled render targets
379   mDownsampledWidth = mTargetSize.width * mDownsampleWidthScale;
380   mDownsampledHeight = mTargetSize.height * mDownsampleHeightScale;
381
382   // Create and place a camera for the renders corresponding to the (potentially downsampled) render targets' size
383   mRenderDownsampledCamera.SetFieldOfView(ARBITRARY_FIELD_OF_VIEW);
384   // 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
385   mRenderDownsampledCamera.SetNearClippingPlane(1.0f);
386   mRenderDownsampledCamera.SetAspectRatio(mDownsampledWidth / mDownsampledHeight);
387   mRenderDownsampledCamera.SetType(Dali::Camera::FREE_LOOK); // camera orientation based solely on actor
388
389   mRenderDownsampledCamera.SetProperty( Actor::Property::POSITION, Vector3(0.0f, 0.0f, ((mDownsampledHeight * 0.5f) / tanf(ARBITRARY_FIELD_OF_VIEW * 0.5f))));
390
391   // setup for normal operation
392   if(!mBlurUserImage)
393   {
394     // Create and place a camera for the children render, corresponding to its render target size
395     mRenderFullSizeCamera.SetFieldOfView(ARBITRARY_FIELD_OF_VIEW);
396     // 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
397     mRenderFullSizeCamera.SetNearClippingPlane(1.0f);
398     mRenderFullSizeCamera.SetAspectRatio(mTargetSize.width / mTargetSize.height);
399     mRenderFullSizeCamera.SetType(Dali::Camera::FREE_LOOK); // camera orientation based solely on actor
400
401     float cameraPosConstraintScale = 0.5f / tanf(ARBITRARY_FIELD_OF_VIEW * 0.5f);
402     mRenderFullSizeCamera.SetProperty( Actor::Property::POSITION, Vector3(0.0f, 0.0f, mTargetSize.height * cameraPosConstraintScale));
403
404     // create offscreen buffer of new size to render our child actors to
405     mRenderTargetForRenderingChildren = FrameBuffer::New( mTargetSize.width, mTargetSize.height, FrameBuffer::Attachment::NONE );
406     Texture texture = Texture::New( TextureType::TEXTURE_2D, mPixelFormat, unsigned(mTargetSize.width), unsigned(mTargetSize.height) );
407     mRenderTargetForRenderingChildren.AttachColorTexture( texture );
408
409     // Set actor for performing a horizontal blur
410     SetRendererTexture( mHorizBlurActor.GetRendererAt(0), mRenderTargetForRenderingChildren );
411
412     // Create offscreen buffer for vert blur pass
413     mRenderTarget1 = FrameBuffer::New( mDownsampledWidth, mDownsampledHeight, FrameBuffer::Attachment::NONE );
414     texture = Texture::New(TextureType::TEXTURE_2D, mPixelFormat, unsigned(mDownsampledWidth), unsigned(mDownsampledHeight));
415     mRenderTarget1.AttachColorTexture( texture );
416
417     // use the completed blur in the first buffer and composite with the original child actors render
418     SetRendererTexture( mCompositingActor.GetRendererAt(0), mRenderTarget1 );
419
420     // set up target actor for rendering result, i.e. the blurred image
421     SetRendererTexture( mTargetActor.GetRendererAt(0), mRenderTargetForRenderingChildren );
422   }
423
424   // Create offscreen buffer for horiz blur pass
425   mRenderTarget2 = FrameBuffer::New( mDownsampledWidth, mDownsampledHeight, FrameBuffer::Attachment::NONE );
426   Texture texture = Texture::New(TextureType::TEXTURE_2D, mPixelFormat, unsigned(mDownsampledWidth), unsigned(mDownsampledHeight));
427   mRenderTarget2.AttachColorTexture( texture );
428
429   // size needs to match render target
430   mHorizBlurActor.SetProperty( Actor::Property::SIZE, Vector2(mDownsampledWidth, mDownsampledHeight) );
431
432   // size needs to match render target
433   mVertBlurActor.SetProperty( Actor::Property::SIZE, Vector2(mDownsampledWidth, mDownsampledHeight) );
434   SetRendererTexture( mVertBlurActor.GetRendererAt(0), mRenderTarget2 );
435
436   // set gaussian blur up for new sized render targets
437   SetShaderConstants();
438 }
439
440 void GaussianBlurView::CreateRenderTasks()
441 {
442   RenderTaskList taskList = Stage::GetCurrent().GetRenderTaskList();
443
444   if(!mBlurUserImage)
445   {
446     // create render task to render our child actors to offscreen buffer
447     mRenderChildrenTask = taskList.CreateTask();
448     mRenderChildrenTask.SetSourceActor( mChildrenRoot );
449     mRenderChildrenTask.SetExclusive(true);
450     mRenderChildrenTask.SetInputEnabled( false );
451     mRenderChildrenTask.SetClearEnabled( true );
452     mRenderChildrenTask.SetClearColor( mBackgroundColor );
453
454     mRenderChildrenTask.SetCameraActor(mRenderFullSizeCamera);
455     mRenderChildrenTask.SetFrameBuffer( mRenderTargetForRenderingChildren );
456
457     if( mRenderOnce )
458     {
459       mRenderChildrenTask.SetRefreshRate(RenderTask::REFRESH_ONCE);
460     }
461   }
462
463   // perform a horizontal blur targeting the second buffer
464   mHorizBlurTask = taskList.CreateTask();
465   mHorizBlurTask.SetSourceActor( mHorizBlurActor );
466   mHorizBlurTask.SetExclusive(true);
467   mHorizBlurTask.SetInputEnabled( false );
468   mHorizBlurTask.SetClearEnabled( true );
469   mHorizBlurTask.SetClearColor( mBackgroundColor );
470   mHorizBlurTask.SetCameraActor(mRenderDownsampledCamera);
471   mHorizBlurTask.SetFrameBuffer( mRenderTarget2 );
472   if( mRenderOnce || ( mRenderOnce && mBlurUserImage ) )
473   {
474     mHorizBlurTask.SetRefreshRate(RenderTask::REFRESH_ONCE);
475   }
476
477   // use the second buffer and perform a horizontal blur targeting the first buffer
478   mVertBlurTask = taskList.CreateTask();
479   mVertBlurTask.SetSourceActor( mVertBlurActor );
480   mVertBlurTask.SetExclusive(true);
481   mVertBlurTask.SetInputEnabled( false );
482   mVertBlurTask.SetClearEnabled( true );
483   mVertBlurTask.SetClearColor( mBackgroundColor );
484   mVertBlurTask.SetCameraActor(mRenderDownsampledCamera);
485   if(mUserOutputRenderTarget)
486   {
487     mVertBlurTask.SetFrameBuffer( mUserOutputRenderTarget );
488   }
489   else
490   {
491     mVertBlurTask.SetFrameBuffer( mRenderTarget1 );
492   }
493   if( mRenderOnce || ( mRenderOnce && mBlurUserImage ) )
494   {
495     mVertBlurTask.SetRefreshRate(RenderTask::REFRESH_ONCE);
496     mVertBlurTask.FinishedSignal().Connect( this, &GaussianBlurView::OnRenderTaskFinished );
497   }
498
499   // use the completed blur in the first buffer and composite with the original child actors render
500   if(!mBlurUserImage)
501   {
502     mCompositeTask = taskList.CreateTask();
503     mCompositeTask.SetSourceActor( mCompositingActor );
504     mCompositeTask.SetExclusive(true);
505     mCompositeTask.SetInputEnabled( false );
506
507     mCompositeTask.SetCameraActor(mRenderFullSizeCamera);
508     mCompositeTask.SetFrameBuffer( mRenderTargetForRenderingChildren );
509
510     if( mRenderOnce )
511     {
512       mCompositeTask.SetRefreshRate(RenderTask::REFRESH_ONCE);
513     }
514   }
515 }
516
517 void GaussianBlurView::RemoveRenderTasks()
518 {
519   RenderTaskList taskList = Stage::GetCurrent().GetRenderTaskList();
520
521   taskList.RemoveTask(mRenderChildrenTask);
522   taskList.RemoveTask(mHorizBlurTask);
523   taskList.RemoveTask(mVertBlurTask);
524   taskList.RemoveTask(mCompositeTask);
525 }
526
527 void GaussianBlurView::Activate()
528 {
529   if( !mActivated )
530   {
531     // make sure resources are allocated and start the render tasks processing
532     Self().Add( mInternalRoot );
533     AllocateResources();
534     CreateRenderTasks();
535     mActivated = true;
536   }
537 }
538
539 void GaussianBlurView::ActivateOnce()
540 {
541   Deactivate();
542   mRenderOnce = true;
543   Activate();
544 }
545
546 void GaussianBlurView::Deactivate()
547 {
548   if( mActivated )
549   {
550     // stop render tasks processing
551     // Note: render target resources are automatically freed since we set the Image::Unused flag
552     mInternalRoot.Unparent();
553     mRenderTargetForRenderingChildren.Reset();
554     mRenderTarget1.Reset();
555     mRenderTarget2.Reset();
556     RemoveRenderTasks();
557     mRenderOnce = false;
558     mActivated = false;
559   }
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