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