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