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