Update toolkit with ResourceImage/Image split
[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/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
260   //////////////////////////////////////////////////////
261   // Create shaders
262
263   // horiz
264   std::ostringstream horizFragmentShaderStringStream;
265   horizFragmentShaderStringStream << "#define NUM_SAMPLES " << mNumSamples << "\n";
266   horizFragmentShaderStringStream << GAUSSIAN_BLUR_FRAGMENT_SOURCE;
267   mHorizBlurShader = ShaderEffect::New( "", horizFragmentShaderStringStream.str() );
268   // vert
269   std::ostringstream vertFragmentShaderStringStream;
270   vertFragmentShaderStringStream << "#define NUM_SAMPLES " << mNumSamples << "\n";
271   vertFragmentShaderStringStream << GAUSSIAN_BLUR_FRAGMENT_SOURCE;
272   mVertBlurShader = ShaderEffect::New( "", vertFragmentShaderStringStream.str() );
273
274
275   //////////////////////////////////////////////////////
276   // Create actors
277
278   // Create an ImageActor for performing a horizontal blur on the texture
279   mImageActorHorizBlur = ImageActor::New();
280   mImageActorHorizBlur.SetParentOrigin(ParentOrigin::CENTER);
281   mImageActorHorizBlur.ScaleBy( Vector3(1.0f, -1.0f, 1.0f) ); // FIXME
282   mImageActorHorizBlur.SetShaderEffect( mHorizBlurShader );
283
284   // Create an ImageActor for performing a vertical blur on the texture
285   mImageActorVertBlur = ImageActor::New();
286   mImageActorVertBlur.SetParentOrigin(ParentOrigin::CENTER);
287   mImageActorVertBlur.ScaleBy( Vector3(1.0f, -1.0f, 1.0f) ); // FIXME
288   mImageActorVertBlur.SetShaderEffect( mVertBlurShader );
289
290   // Register a property that the user can control to fade the blur in / out via the GaussianBlurView object
291   mBlurStrengthPropertyIndex = Self().RegisterProperty(GAUSSIAN_BLUR_VIEW_STRENGTH_PROPERTY_NAME, GAUSSIAN_BLUR_VIEW_DEFAULT_BLUR_STRENGTH);
292
293   // Create an ImageActor for compositing the blur and the original child actors render
294   if(!mBlurUserImage)
295   {
296     mImageActorComposite = ImageActor::New();
297     mImageActorComposite.SetParentOrigin(ParentOrigin::CENTER);
298     mImageActorComposite.ScaleBy( Vector3(1.0f, -1.0f, 1.0f) ); // FIXME
299     mImageActorComposite.SetOpacity(GAUSSIAN_BLUR_VIEW_DEFAULT_BLUR_STRENGTH); // ensure alpha is enabled for this object and set default value
300
301     Constraint blurStrengthConstraint = Constraint::New<float>( Actor::COLOR_ALPHA, ParentSource(mBlurStrengthPropertyIndex), EqualToConstraintFloat());
302     mImageActorComposite.ApplyConstraint(blurStrengthConstraint);
303
304     // Create an ImageActor for holding final result, i.e. the blurred image. This will get rendered to screen later, via default / user render task
305     mTargetActor = ImageActor::New();
306     mTargetActor.SetParentOrigin(ParentOrigin::CENTER);
307     mTargetActor.ScaleBy( Vector3(1.0f, -1.0f, 1.0f) ); // FIXME
308
309
310     //////////////////////////////////////////////////////
311     // Create cameras for the renders corresponding to the view size
312     mRenderFullSizeCamera = CameraActor::New();
313     mRenderFullSizeCamera.SetParentOrigin(ParentOrigin::CENTER);
314
315
316     //////////////////////////////////////////////////////
317     // Connect to actor tree
318     Self().Add( mImageActorComposite );
319     Self().Add( mTargetActor );
320     Self().Add( mRenderFullSizeCamera );
321   }
322
323
324   //////////////////////////////////////////////////////
325   // Create camera for the renders corresponding to the (potentially downsampled) render targets' size
326   mRenderDownsampledCamera = CameraActor::New();
327   mRenderDownsampledCamera.SetParentOrigin(ParentOrigin::CENTER);
328
329
330   //////////////////////////////////////////////////////
331   // Connect to actor tree
332   Self().Add( mChildrenRoot );
333   Self().Add( mImageActorHorizBlur );
334   Self().Add( mImageActorVertBlur );
335   Self().Add( mRenderDownsampledCamera );
336 }
337
338
339 /**
340  * ZrelativeToYconstraint
341  *
342  * f(current, property, scale) = Vector3(current.x, current.y, property.y * scale)
343  */
344 struct ZrelativeToYconstraint
345 {
346   ZrelativeToYconstraint( float scale )
347     : mScale( scale )
348   {}
349
350   Vector3 operator()(const Vector3&    current,
351                      const PropertyInput& property)
352   {
353     Vector3 v;
354
355     v.x = current.x;
356     v.y = current.y;
357     v.z = property.GetVector3().y * mScale;
358
359     return v;
360   }
361
362   float mScale;
363 };
364
365 void GaussianBlurView::OnControlSizeSet(const Vector3& targetSize)
366 {
367   mTargetSize = Vector2(targetSize);
368
369   mChildrenRoot.SetSize(targetSize);
370
371   if( !mBlurUserImage )
372   {
373     mImageActorComposite.SetSize(targetSize);
374     mTargetActor.SetSize(targetSize);
375
376     // 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
377     // 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
378     // size, this is the trade off for not being able to modify render target size
379     // Change camera z position based on GaussianBlurView actor height
380     float cameraPosConstraintScale = 0.5f / tanf(ARBITRARY_FIELD_OF_VIEW * 0.5f);
381     mRenderFullSizeCamera.SetZ(mTargetSize.height * cameraPosConstraintScale);
382   }
383
384
385   // if we are already on stage, need to update render target sizes now to reflect the new size of this actor
386   if(Self().OnStage())
387   {
388     AllocateResources();
389   }
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     // Point the camera back into the scene
410     mRenderDownsampledCamera.SetRotation(Quaternion(M_PI, Vector3::YAXIS));
411
412     mRenderDownsampledCamera.SetPosition(0.0f, 0.0f, ((mDownsampledHeight * 0.5f) / tanf(ARBITRARY_FIELD_OF_VIEW * 0.5f)));
413
414     // setup for normal operation
415     if(!mBlurUserImage)
416     {
417       // Create and place a camera for the children render, corresponding to its render target size
418       mRenderFullSizeCamera.SetFieldOfView(ARBITRARY_FIELD_OF_VIEW);
419       // 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
420       mRenderFullSizeCamera.SetNearClippingPlane(1.0f);
421       mRenderFullSizeCamera.SetAspectRatio(mTargetSize.width / mTargetSize.height);
422       mRenderFullSizeCamera.SetType(Dali::Camera::FREE_LOOK); // camera orientation based solely on actor
423       // Point the camera back into the scene
424       mRenderFullSizeCamera.SetRotation(Quaternion(M_PI, Vector3::YAXIS));
425
426       float cameraPosConstraintScale = 0.5f / tanf(ARBITRARY_FIELD_OF_VIEW * 0.5f);
427       mRenderFullSizeCamera.SetPosition(0.0f, 0.0f, mTargetSize.height * cameraPosConstraintScale);
428
429       // create offscreen buffer of new size to render our child actors to
430       mRenderTargetForRenderingChildren = FrameBufferImage::New( mTargetSize.width, mTargetSize.height, mPixelFormat, Dali::Image::UNUSED );
431
432       // Set ImageActor for performing a horizontal blur on the texture
433       mImageActorHorizBlur.SetImage( mRenderTargetForRenderingChildren );
434
435       // Create offscreen buffer for vert blur pass
436       mRenderTarget1 = FrameBufferImage::New( mDownsampledWidth, mDownsampledHeight, mPixelFormat, Dali::Image::UNUSED );
437
438       // use the completed blur in the first buffer and composite with the original child actors render
439       mImageActorComposite.SetImage( mRenderTarget1 );
440
441       // set up target actor for rendering result, i.e. the blurred image
442       mTargetActor.SetImage(mRenderTargetForRenderingChildren);
443     }
444
445     // Create offscreen buffer for horiz blur pass
446     mRenderTarget2 = FrameBufferImage::New( mDownsampledWidth, mDownsampledHeight, mPixelFormat, Dali::Image::UNUSED );
447
448     // size needs to match render target
449     mImageActorHorizBlur.SetSize(mDownsampledWidth, mDownsampledHeight);
450
451     // size needs to match render target
452     mImageActorVertBlur.SetImage( mRenderTarget2 );
453     mImageActorVertBlur.SetSize(mDownsampledWidth, mDownsampledHeight);
454
455     // set gaussian blur up for new sized render targets
456     SetShaderConstants();
457   }
458 }
459
460 void GaussianBlurView::CreateRenderTasks()
461 {
462   RenderTaskList taskList = Stage::GetCurrent().GetRenderTaskList();
463
464   if(!mBlurUserImage)
465   {
466     // create render task to render our child actors to offscreen buffer
467     mRenderChildrenTask = taskList.CreateTask();
468     mRenderChildrenTask.SetSourceActor( mChildrenRoot );
469     mRenderChildrenTask.SetExclusive(true);
470     mRenderChildrenTask.SetInputEnabled( false );
471     mRenderChildrenTask.SetClearEnabled( true );
472     mRenderChildrenTask.SetClearColor( mBackgroundColor );
473
474     mRenderChildrenTask.SetCameraActor(mRenderFullSizeCamera);
475     mRenderChildrenTask.SetTargetFrameBuffer( mRenderTargetForRenderingChildren );
476   }
477
478   // perform a horizontal blur targeting the second buffer
479   mHorizBlurTask = taskList.CreateTask();
480   mHorizBlurTask.SetSourceActor( mImageActorHorizBlur );
481   mHorizBlurTask.SetExclusive(true);
482   mHorizBlurTask.SetInputEnabled( false );
483   mHorizBlurTask.SetClearEnabled( true );
484   mHorizBlurTask.SetClearColor( mBackgroundColor );
485   if( mRenderOnce && mBlurUserImage )
486   {
487     mHorizBlurTask.SetRefreshRate(RenderTask::REFRESH_ONCE);
488   }
489
490   // use the second buffer and perform a horizontal blur targeting the first buffer
491   mVertBlurTask = taskList.CreateTask();
492   mVertBlurTask.SetSourceActor( mImageActorVertBlur );
493   mVertBlurTask.SetExclusive(true);
494   mVertBlurTask.SetInputEnabled( false );
495   mVertBlurTask.SetClearEnabled( true );
496   mVertBlurTask.SetClearColor( mBackgroundColor );
497   if( mRenderOnce && mBlurUserImage )
498   {
499     mVertBlurTask.SetRefreshRate(RenderTask::REFRESH_ONCE);
500     mVertBlurTask.FinishedSignal().Connect( this, &GaussianBlurView::OnRenderTaskFinished );
501   }
502
503   // use the completed blur in the first buffer and composite with the original child actors render
504   if(!mBlurUserImage)
505   {
506     mCompositeTask = taskList.CreateTask();
507     mCompositeTask.SetSourceActor( mImageActorComposite );
508     mCompositeTask.SetExclusive(true);
509     mCompositeTask.SetInputEnabled( false );
510
511     mCompositeTask.SetCameraActor(mRenderFullSizeCamera);
512     mCompositeTask.SetTargetFrameBuffer( mRenderTargetForRenderingChildren );
513   }
514
515   mHorizBlurTask.SetCameraActor(mRenderDownsampledCamera);
516   mVertBlurTask.SetCameraActor(mRenderDownsampledCamera);
517
518   mHorizBlurTask.SetTargetFrameBuffer( mRenderTarget2 );
519   if(mUserOutputRenderTarget)
520   {
521     mVertBlurTask.SetTargetFrameBuffer( mUserOutputRenderTarget );
522   }
523   else
524   {
525     mVertBlurTask.SetTargetFrameBuffer( mRenderTarget1 );
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::OnStageDisconnection()
540 {
541   // TODO: can't call this here, since SetImage() calls fails similarly to above
542   // 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()
543   //Deactivate();
544 }
545
546 void GaussianBlurView::OnControlStageConnection()
547 {
548   // TODO: can't call this here, since SetImage() calls fail to connect images to stage, since parent chain not fully on stage yet
549   // 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()
550   //Activate();
551 }
552
553 void GaussianBlurView::Activate()
554 {
555   // make sure resources are allocated and start the render tasks processing
556   AllocateResources();
557   CreateRenderTasks();
558 }
559
560 void GaussianBlurView::ActivateOnce()
561 {
562   DALI_ASSERT_ALWAYS(mBlurUserImage); // Only works with blurring image mode.
563   mRenderOnce = true;
564   Activate();
565 }
566
567 void GaussianBlurView::Deactivate()
568 {
569   // stop render tasks processing
570   // Note: render target resources are automatically freed since we set the Image::Unused flag
571   RemoveRenderTasks();
572   mRenderOnce = false;
573 }
574
575 void GaussianBlurView::SetBlurBellCurveWidth(float blurBellCurveWidth)
576 {
577   // a value of zero leads to undefined Gaussian weights, do not allow user to do this
578   mBlurBellCurveWidth = std::max( blurBellCurveWidth, 0.001f );
579 }
580
581 float GaussianBlurView::CalcGaussianWeight(float x)
582 {
583   return (1.0f / sqrt(2.0f * Math::PI * mBlurBellCurveWidth)) * exp(-(x * x) / (2.0f * mBlurBellCurveWidth * mBlurBellCurveWidth));
584 }
585
586 void GaussianBlurView::SetShaderConstants()
587 {
588   Vector2 *uvOffsets;
589   float ofs;
590   float *weights;
591   float w, totalWeights;
592   unsigned int i;
593
594   uvOffsets = new Vector2[mNumSamples + 1];
595   weights = new float[mNumSamples + 1];
596
597   totalWeights = weights[0] = CalcGaussianWeight(0);
598   uvOffsets[0].x = 0.0f;
599   uvOffsets[0].y = 0.0f;
600
601   for(i=0; i<mNumSamples >> 1; i++)
602   {
603     w = CalcGaussianWeight((float)(i + 1));
604     weights[(i << 1) + 1] = w;
605     weights[(i << 1) + 2] = w;
606     totalWeights += w * 2.0f;
607
608     // offset texture lookup to between texels, that way the bilinear filter in the texture hardware will average two samples with one lookup
609     ofs = ((float)(i << 1)) + 1.5f;
610
611     // get offsets from units of pixels into uv coordinates in [0..1]
612     float ofsX = ofs / mDownsampledWidth;
613     float ofsY = ofs / mDownsampledHeight;
614     uvOffsets[(i << 1) + 1].x = ofsX;
615     uvOffsets[(i << 1) + 1].y = ofsY;
616
617     uvOffsets[(i << 1) + 2].x = -ofsX;
618     uvOffsets[(i << 1) + 2].y = -ofsY;
619   }
620
621   for(i=0; i<mNumSamples; i++)
622   {
623     weights[i] /= totalWeights;
624   }
625
626   // set shader constants
627   Vector2 xAxis(1.0f, 0.0f);
628   Vector2 yAxis(0.0f, 1.0f);
629   for (i = 0; i < mNumSamples; ++i )
630   {
631     mHorizBlurShader.SetUniform( GetSampleOffsetsPropertyName( i ), uvOffsets[ i ] * xAxis );
632     mHorizBlurShader.SetUniform( GetSampleWeightsPropertyName( i ), weights[ i ] );
633
634     mVertBlurShader.SetUniform( GetSampleOffsetsPropertyName( i ), uvOffsets[ i ] * yAxis );
635     mVertBlurShader.SetUniform( GetSampleWeightsPropertyName( i ), weights[ i ] );
636   }
637
638   delete[] uvOffsets;
639   delete[] weights;
640 }
641
642 std::string GaussianBlurView::GetSampleOffsetsPropertyName( unsigned int index ) const
643 {
644   DALI_ASSERT_ALWAYS( index < mNumSamples );
645
646   std::ostringstream oss;
647   oss << "uSampleOffsets[" << index << "]";
648   return oss.str();
649 }
650
651 std::string GaussianBlurView::GetSampleWeightsPropertyName( unsigned int index ) const
652 {
653   DALI_ASSERT_ALWAYS( index < mNumSamples );
654
655   std::ostringstream oss;
656   oss << "uSampleWeights[" << index << "]";
657   return oss.str();
658 }
659
660 Dali::Toolkit::GaussianBlurView::GaussianBlurViewSignal& GaussianBlurView::FinishedSignal()
661 {
662   return mFinishedSignal;
663 }
664
665 void GaussianBlurView::OnRenderTaskFinished(Dali::RenderTask& renderTask)
666 {
667   Toolkit::GaussianBlurView handle( GetOwner() );
668   mFinishedSignal.Emit( handle );
669 }
670
671 } // namespace Internal
672 } // namespace Toolkit
673 } // namespace Dali