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