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