Stop using ImageActor in GaussianBlur, Bloom & SuperBlur
[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/property-map.h>
28 #include <dali/public-api/object/type-registry.h>
29 #include <dali/devel-api/object/type-registry-helper.h>
30 #include <dali/public-api/render-tasks/render-task-list.h>
31 #include <dali/integration-api/debug.h>
32
33 // INTERNAL INCLUDES
34 #include <dali-toolkit/public-api/controls/gaussian-blur-view/gaussian-blur-view.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 // mChildrenRoot Add()/Remove() overloads - better solution
41 // Manager object - re-use render targets if there are multiple GaussianBlurViews created
42
43
44 /////////////////////////////////////////////////////////
45 // IMPLEMENTATION NOTES
46
47 // As the GaussianBlurView actor changes size, the amount of pixels we need to blur changes. Therefore we need some way of doing this. However:-
48 // OnSetSize() does not get called when GaussianBlurView object size is modified using a Constraint.
49 // 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
50 // OnSizeAnimation() to alter render target sizes.
51 // 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
52 // 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
53 // by using constraints relative to the GaussianBlurView actor size.
54
55
56 // 2 modes:
57 // 1st mode, this control has a tree of actors (use Add() to add children) that are rendered and blurred.
58 // mRenderChildrenTask renders children to FB mRenderTargetForRenderingChildren
59 // mHorizBlurTask renders mImageActorHorizBlur Actor showing FB mRenderTargetForRenderingChildren into FB mRenderTarget2
60 // mVertBlurTask renders mImageActorVertBlur Actor showing FB mRenderTarget2 into FB mRenderTarget1
61 // mCompositeTask renders mImageActorComposite Actor showing FB mRenderTarget1 into FB mRenderTargetForRenderingChildren
62 //
63 // 2nd mode, an image is blurred and rendered to a supplied target framebuffer
64 // mHorizBlurTask renders mImageActorHorizBlur Actor showing mUserInputImage into FB mRenderTarget2
65 // mVertBlurTask renders mImageActorVertBlur Actor showing mRenderTarget2 into FB mUserOutputRenderTarget
66 //
67 // Only this 2nd mode handles ActivateOnce
68
69 namespace Dali
70 {
71
72 namespace Toolkit
73 {
74
75 namespace Internal
76 {
77
78 namespace
79 {
80
81 using namespace Dali;
82
83 BaseHandle Create()
84 {
85   return Toolkit::GaussianBlurView::New();
86 }
87
88 DALI_TYPE_REGISTRATION_BEGIN( Toolkit::GaussianBlurView, Toolkit::Control, Create )
89 DALI_TYPE_REGISTRATION_END()
90
91 const unsigned int GAUSSIAN_BLUR_VIEW_DEFAULT_NUM_SAMPLES = 5;
92 const float GAUSSIAN_BLUR_VIEW_DEFAULT_BLUR_BELL_CURVE_WIDTH = 1.5f;
93 const Pixel::Format GAUSSIAN_BLUR_VIEW_DEFAULT_RENDER_TARGET_PIXEL_FORMAT = Pixel::RGBA8888;
94 const float GAUSSIAN_BLUR_VIEW_DEFAULT_BLUR_STRENGTH = 1.0f;                                       // default, fully blurred
95 const char* const GAUSSIAN_BLUR_VIEW_STRENGTH_PROPERTY_NAME = "GaussianBlurStrengthPropertyName";
96 const float GAUSSIAN_BLUR_VIEW_DEFAULT_DOWNSAMPLE_WIDTH_SCALE = 0.5f;
97 const float GAUSSIAN_BLUR_VIEW_DEFAULT_DOWNSAMPLE_HEIGHT_SCALE = 0.5f;
98
99 const float ARBITRARY_FIELD_OF_VIEW = Math::PI / 4.0f;
100
101 const char* const GAUSSIAN_BLUR_FRAGMENT_SOURCE =
102     "varying mediump vec2 vTexCoord;\n"
103     "uniform sampler2D sTexture;\n"
104     "uniform lowp vec4 uColor;\n"
105     "uniform mediump vec2 uSampleOffsets[NUM_SAMPLES];\n"
106     "uniform mediump float uSampleWeights[NUM_SAMPLES];\n"
107
108     "void main()\n"
109     "{\n"
110     "   mediump vec4 col = texture2D(sTexture, vTexCoord + uSampleOffsets[0]) * uSampleWeights[0];\n"
111     "   for (int i=1; i<NUM_SAMPLES; ++i)\n"
112     "   {\n"
113     "     col += texture2D(sTexture, vTexCoord + uSampleOffsets[i]) * uSampleWeights[i];\n"
114     "   }\n"
115     "   gl_FragColor = col;\n"
116     "}\n";
117
118 } // namespace
119
120
121 GaussianBlurView::GaussianBlurView()
122   : Control( ControlBehaviour( DISABLE_SIZE_NEGOTIATION ) )
123   , mNumSamples(GAUSSIAN_BLUR_VIEW_DEFAULT_NUM_SAMPLES)
124   , mBlurBellCurveWidth( 0.001f )
125   , mPixelFormat(GAUSSIAN_BLUR_VIEW_DEFAULT_RENDER_TARGET_PIXEL_FORMAT)
126   , mDownsampleWidthScale(GAUSSIAN_BLUR_VIEW_DEFAULT_DOWNSAMPLE_WIDTH_SCALE)
127   , mDownsampleHeightScale(GAUSSIAN_BLUR_VIEW_DEFAULT_DOWNSAMPLE_HEIGHT_SCALE)
128   , mDownsampledWidth( 0.0f )
129   , mDownsampledHeight( 0.0f )
130   , mBlurUserImage( false )
131   , mRenderOnce( false )
132   , mBackgroundColor( Color::BLACK )
133   , mTargetSize(Vector2::ZERO)
134   , mLastSize(Vector2::ZERO)
135   , mChildrenRoot(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   , 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 // 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.
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   mImageActorHorizBlur.SetImage( mUserInputImage );
220
221   mUserOutputRenderTarget = outputRenderTarget;
222 }
223
224 FrameBufferImage GaussianBlurView::GetBlurredRenderTarget() const
225 {
226   if(!mUserOutputRenderTarget)
227   {
228     return mRenderTargetForRenderingChildren;
229   }
230
231   return mUserOutputRenderTarget;
232 }
233
234 void GaussianBlurView::SetBackgroundColor( const Vector4& color )
235 {
236   mBackgroundColor = color;
237 }
238
239 Vector4 GaussianBlurView::GetBackgroundColor() const
240 {
241   return mBackgroundColor;
242 }
243
244 ///////////////////////////////////////////////////////////
245 //
246 // Private methods
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
254   //////////////////////////////////////////////////////
255   // Create shaders
256
257   std::ostringstream horizFragmentShaderStringStream;
258   horizFragmentShaderStringStream << "#define NUM_SAMPLES " << mNumSamples << "\n";
259   horizFragmentShaderStringStream << GAUSSIAN_BLUR_FRAGMENT_SOURCE;
260   Property::Map customShader;
261   customShader[ "fragmentShader" ] = horizFragmentShaderStringStream.str();
262   Property::Map rendererMap;
263   rendererMap.Insert( "rendererType", "imageRenderer" );
264   rendererMap.Insert( "shader", customShader );
265
266   //////////////////////////////////////////////////////
267   // Create actors
268
269   // Create an ImageActor for performing a horizontal blur on the texture
270   mImageActorHorizBlur = Toolkit::ImageView::New();
271   mImageActorHorizBlur.SetParentOrigin(ParentOrigin::CENTER);
272   mImageActorHorizBlur.SetProperty( Toolkit::ImageView::Property::IMAGE, rendererMap );
273
274   // Create an ImageActor for performing a vertical blur on the texture
275   mImageActorVertBlur = Toolkit::ImageView::New();
276   mImageActorVertBlur.SetParentOrigin(ParentOrigin::CENTER);
277   mImageActorVertBlur.SetProperty( Toolkit::ImageView::Property::IMAGE, rendererMap );
278
279   // Register a property that the user can control to fade the blur in / out via the GaussianBlurView object
280   mBlurStrengthPropertyIndex = Self().RegisterProperty(GAUSSIAN_BLUR_VIEW_STRENGTH_PROPERTY_NAME, GAUSSIAN_BLUR_VIEW_DEFAULT_BLUR_STRENGTH);
281
282   // Create an ImageActor for compositing the blur and the original child actors render
283   if(!mBlurUserImage)
284   {
285     mImageActorComposite = Toolkit::ImageView::New();
286     mImageActorComposite.SetParentOrigin(ParentOrigin::CENTER);
287     mImageActorComposite.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>( mImageActorComposite, Actor::Property::COLOR_ALPHA, EqualToConstraint());
290     blurStrengthConstraint.AddSource( ParentSource(mBlurStrengthPropertyIndex) );
291     blurStrengthConstraint.Apply();
292
293     // Create an ImageActor 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     Self().Add( mImageActorComposite );
307     Self().Add( mTargetActor );
308     Self().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( mImageActorHorizBlur );
323   Self().Add( mImageActorVertBlur );
324   Self().Add( mRenderDownsampledCamera );
325 }
326
327
328 void GaussianBlurView::OnSizeSet(const Vector3& targetSize)
329 {
330   mTargetSize = Vector2(targetSize);
331
332   mChildrenRoot.SetSize(targetSize);
333
334   if( !mBlurUserImage )
335   {
336     mImageActorComposite.SetSize(targetSize);
337     mTargetActor.SetSize(targetSize);
338
339     // 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
340     // 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
341     // size, this is the trade off for not being able to modify render target size
342     // Change camera z position based on GaussianBlurView actor height
343     float cameraPosConstraintScale = 0.5f / tanf(ARBITRARY_FIELD_OF_VIEW * 0.5f);
344     mRenderFullSizeCamera.SetZ(mTargetSize.height * cameraPosConstraintScale);
345   }
346
347
348   // if we have already activated the blur, need to update render target sizes now to reflect the new size of this actor
349   if(mActivated)
350   {
351     Deactivate();
352     Activate();
353   }
354 }
355
356 void GaussianBlurView::AllocateResources()
357 {
358   // size of render targets etc is based on the size of this actor, ignoring z
359   if(mTargetSize != mLastSize)
360   {
361     mLastSize = mTargetSize;
362
363     // get size of downsampled render targets
364     mDownsampledWidth = mTargetSize.width * mDownsampleWidthScale;
365     mDownsampledHeight = mTargetSize.height * mDownsampleHeightScale;
366
367     // Create and place a camera for the renders corresponding to the (potentially downsampled) render targets' size
368     mRenderDownsampledCamera.SetFieldOfView(ARBITRARY_FIELD_OF_VIEW);
369     // 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
370     mRenderDownsampledCamera.SetNearClippingPlane(1.0f);
371     mRenderDownsampledCamera.SetAspectRatio(mDownsampledWidth / mDownsampledHeight);
372     mRenderDownsampledCamera.SetType(Dali::Camera::FREE_LOOK); // camera orientation based solely on actor
373
374     mRenderDownsampledCamera.SetPosition(0.0f, 0.0f, ((mDownsampledHeight * 0.5f) / tanf(ARBITRARY_FIELD_OF_VIEW * 0.5f)));
375
376     // setup for normal operation
377     if(!mBlurUserImage)
378     {
379       // Create and place a camera for the children render, corresponding to its render target size
380       mRenderFullSizeCamera.SetFieldOfView(ARBITRARY_FIELD_OF_VIEW);
381       // 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
382       mRenderFullSizeCamera.SetNearClippingPlane(1.0f);
383       mRenderFullSizeCamera.SetAspectRatio(mTargetSize.width / mTargetSize.height);
384       mRenderFullSizeCamera.SetType(Dali::Camera::FREE_LOOK); // camera orientation based solely on actor
385
386       float cameraPosConstraintScale = 0.5f / tanf(ARBITRARY_FIELD_OF_VIEW * 0.5f);
387       mRenderFullSizeCamera.SetPosition(0.0f, 0.0f, mTargetSize.height * cameraPosConstraintScale);
388
389       // create offscreen buffer of new size to render our child actors to
390       mRenderTargetForRenderingChildren = FrameBufferImage::New( mTargetSize.width, mTargetSize.height, mPixelFormat );
391
392       // Set ImageActor for performing a horizontal blur on the texture
393       mImageActorHorizBlur.SetImage( mRenderTargetForRenderingChildren );
394
395       // Create offscreen buffer for vert blur pass
396       mRenderTarget1 = FrameBufferImage::New( mDownsampledWidth, mDownsampledHeight, mPixelFormat );
397
398       // use the completed blur in the first buffer and composite with the original child actors render
399       mImageActorComposite.SetImage( mRenderTarget1 );
400
401       // set up target actor for rendering result, i.e. the blurred image
402       mTargetActor.SetImage(mRenderTargetForRenderingChildren);
403     }
404
405     // Create offscreen buffer for horiz blur pass
406     mRenderTarget2 = FrameBufferImage::New( mDownsampledWidth, mDownsampledHeight, mPixelFormat );
407
408     // size needs to match render target
409     mImageActorHorizBlur.SetSize(mDownsampledWidth, mDownsampledHeight);
410
411     // size needs to match render target
412     mImageActorVertBlur.SetImage( mRenderTarget2 );
413     mImageActorVertBlur.SetSize(mDownsampledWidth, mDownsampledHeight);
414
415     // set gaussian blur up for new sized render targets
416     SetShaderConstants();
417   }
418 }
419
420 void GaussianBlurView::CreateRenderTasks()
421 {
422   RenderTaskList taskList = Stage::GetCurrent().GetRenderTaskList();
423
424   if(!mBlurUserImage)
425   {
426     // create render task to render our child actors to offscreen buffer
427     mRenderChildrenTask = taskList.CreateTask();
428     mRenderChildrenTask.SetSourceActor( mChildrenRoot );
429     mRenderChildrenTask.SetExclusive(true);
430     mRenderChildrenTask.SetInputEnabled( false );
431     mRenderChildrenTask.SetClearEnabled( true );
432     mRenderChildrenTask.SetClearColor( mBackgroundColor );
433
434     mRenderChildrenTask.SetCameraActor(mRenderFullSizeCamera);
435     mRenderChildrenTask.SetTargetFrameBuffer( mRenderTargetForRenderingChildren );
436   }
437
438   // perform a horizontal blur targeting the second buffer
439   mHorizBlurTask = taskList.CreateTask();
440   mHorizBlurTask.SetSourceActor( mImageActorHorizBlur );
441   mHorizBlurTask.SetExclusive(true);
442   mHorizBlurTask.SetInputEnabled( false );
443   mHorizBlurTask.SetClearEnabled( true );
444   mHorizBlurTask.SetClearColor( mBackgroundColor );
445   mHorizBlurTask.SetCameraActor(mRenderDownsampledCamera);
446   mHorizBlurTask.SetTargetFrameBuffer( mRenderTarget2 );
447   if( mRenderOnce && mBlurUserImage )
448   {
449     mHorizBlurTask.SetRefreshRate(RenderTask::REFRESH_ONCE);
450   }
451
452   // use the second buffer and perform a horizontal blur targeting the first buffer
453   mVertBlurTask = taskList.CreateTask();
454   mVertBlurTask.SetSourceActor( mImageActorVertBlur );
455   mVertBlurTask.SetExclusive(true);
456   mVertBlurTask.SetInputEnabled( false );
457   mVertBlurTask.SetClearEnabled( true );
458   mVertBlurTask.SetClearColor( mBackgroundColor );
459   mVertBlurTask.SetCameraActor(mRenderDownsampledCamera);
460   if(mUserOutputRenderTarget)
461   {
462     mVertBlurTask.SetTargetFrameBuffer( mUserOutputRenderTarget );
463   }
464   else
465   {
466     mVertBlurTask.SetTargetFrameBuffer( mRenderTarget1 );
467   }
468   if( mRenderOnce && mBlurUserImage )
469   {
470     mVertBlurTask.SetRefreshRate(RenderTask::REFRESH_ONCE);
471     mVertBlurTask.FinishedSignal().Connect( this, &GaussianBlurView::OnRenderTaskFinished );
472   }
473
474   // use the completed blur in the first buffer and composite with the original child actors render
475   if(!mBlurUserImage)
476   {
477     mCompositeTask = taskList.CreateTask();
478     mCompositeTask.SetSourceActor( mImageActorComposite );
479     mCompositeTask.SetExclusive(true);
480     mCompositeTask.SetInputEnabled( false );
481
482     mCompositeTask.SetCameraActor(mRenderFullSizeCamera);
483     mCompositeTask.SetTargetFrameBuffer( mRenderTargetForRenderingChildren );
484   }
485 }
486
487 void GaussianBlurView::RemoveRenderTasks()
488 {
489   RenderTaskList taskList = Stage::GetCurrent().GetRenderTaskList();
490
491   taskList.RemoveTask(mRenderChildrenTask);
492   taskList.RemoveTask(mHorizBlurTask);
493   taskList.RemoveTask(mVertBlurTask);
494   taskList.RemoveTask(mCompositeTask);
495 }
496
497 void GaussianBlurView::Activate()
498 {
499   // make sure resources are allocated and start the render tasks processing
500   AllocateResources();
501   CreateRenderTasks();
502   mActivated = true;
503 }
504
505 void GaussianBlurView::ActivateOnce()
506 {
507   DALI_ASSERT_ALWAYS(mBlurUserImage); // Only works with blurring image mode.
508   mRenderOnce = true;
509   Activate();
510 }
511
512 void GaussianBlurView::Deactivate()
513 {
514   // stop render tasks processing
515   // Note: render target resources are automatically freed since we set the Image::Unused flag
516   RemoveRenderTasks();
517   mRenderTargetForRenderingChildren.Reset();
518   mRenderTarget1.Reset();
519   mRenderTarget2.Reset();
520   mRenderOnce = false;
521   mActivated = false;
522 }
523
524 void GaussianBlurView::SetBlurBellCurveWidth(float blurBellCurveWidth)
525 {
526   // a value of zero leads to undefined Gaussian weights, do not allow user to do this
527   mBlurBellCurveWidth = std::max( blurBellCurveWidth, 0.001f );
528 }
529
530 float GaussianBlurView::CalcGaussianWeight(float x)
531 {
532   return (1.0f / sqrt(2.0f * Math::PI * mBlurBellCurveWidth)) * exp(-(x * x) / (2.0f * mBlurBellCurveWidth * mBlurBellCurveWidth));
533 }
534
535 void GaussianBlurView::SetShaderConstants()
536 {
537   Vector2 *uvOffsets;
538   float ofs;
539   float *weights;
540   float w, totalWeights;
541   unsigned int i;
542
543   uvOffsets = new Vector2[mNumSamples + 1];
544   weights = new float[mNumSamples + 1];
545
546   totalWeights = weights[0] = CalcGaussianWeight(0);
547   uvOffsets[0].x = 0.0f;
548   uvOffsets[0].y = 0.0f;
549
550   for(i=0; i<mNumSamples >> 1; i++)
551   {
552     w = CalcGaussianWeight((float)(i + 1));
553     weights[(i << 1) + 1] = w;
554     weights[(i << 1) + 2] = w;
555     totalWeights += w * 2.0f;
556
557     // offset texture lookup to between texels, that way the bilinear filter in the texture hardware will average two samples with one lookup
558     ofs = ((float)(i << 1)) + 1.5f;
559
560     // get offsets from units of pixels into uv coordinates in [0..1]
561     float ofsX = ofs / mDownsampledWidth;
562     float ofsY = ofs / mDownsampledHeight;
563     uvOffsets[(i << 1) + 1].x = ofsX;
564     uvOffsets[(i << 1) + 1].y = ofsY;
565
566     uvOffsets[(i << 1) + 2].x = -ofsX;
567     uvOffsets[(i << 1) + 2].y = -ofsY;
568   }
569
570   for(i=0; i<mNumSamples; i++)
571   {
572     weights[i] /= totalWeights;
573   }
574
575   // set shader constants
576   Vector2 xAxis(1.0f, 0.0f);
577   Vector2 yAxis(0.0f, 1.0f);
578   for (i = 0; i < mNumSamples; ++i )
579   {
580     mImageActorHorizBlur.RegisterProperty( GetSampleOffsetsPropertyName( i ), uvOffsets[ i ] * xAxis );
581     mImageActorHorizBlur.RegisterProperty( GetSampleWeightsPropertyName( i ), weights[ i ] );
582
583     mImageActorVertBlur.RegisterProperty( GetSampleOffsetsPropertyName( i ), uvOffsets[ i ] * yAxis );
584     mImageActorVertBlur.RegisterProperty( GetSampleWeightsPropertyName( i ), weights[ i ] );
585   }
586
587   delete[] uvOffsets;
588   delete[] weights;
589 }
590
591 std::string GaussianBlurView::GetSampleOffsetsPropertyName( unsigned int index ) const
592 {
593   DALI_ASSERT_ALWAYS( index < mNumSamples );
594
595   std::ostringstream oss;
596   oss << "uSampleOffsets[" << index << "]";
597   return oss.str();
598 }
599
600 std::string GaussianBlurView::GetSampleWeightsPropertyName( unsigned int index ) const
601 {
602   DALI_ASSERT_ALWAYS( index < mNumSamples );
603
604   std::ostringstream oss;
605   oss << "uSampleWeights[" << index << "]";
606   return oss.str();
607 }
608
609 Dali::Toolkit::GaussianBlurView::GaussianBlurViewSignal& GaussianBlurView::FinishedSignal()
610 {
611   return mFinishedSignal;
612 }
613
614 void GaussianBlurView::OnRenderTaskFinished(Dali::RenderTask& renderTask)
615 {
616   Toolkit::GaussianBlurView handle( GetOwner() );
617   mFinishedSignal.Emit( handle );
618 }
619
620 } // namespace Internal
621 } // namespace Toolkit
622 } // namespace Dali