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