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