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