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