2 // Copyright (c) 2014 Samsung Electronics Co., Ltd.
4 // Licensed under the Flora License, Version 1.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
8 // http://floralicense.org/license/
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.
18 #include "gaussian-blur-view-impl.h"
25 #include <dali-toolkit/public-api/controls/gaussian-blur-view/gaussian-blur-view.h>
27 #include <dali/integration-api/debug.h>
30 // pixel format / size - set from JSON
31 // 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
32 // default near clip value
33 // mChildrenRoot Add()/Remove() overloads - better solution
34 // Manager object - re-use render targets if there are multiple GaussianBlurViews created
38 /////////////////////////////////////////////////////////
39 // IMPLEMENTATION NOTES
41 // As the GaussianBlurView actor changes size, the amount of pixels we need to blur changes. Therefore we need some way of doing this. However:-
42 // OnSetSize() does not get called when GaussianBlurView object size is modified using a Constraint.
43 // 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
44 // OnSizeAnimation() to alter render target sizes.
45 // 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
46 // 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
47 // by using constraints relative to the GaussianBlurView actor size.
51 // 1st mode, this control has a tree of actors (use Add() to add children) that are rendered and blurred.
52 // mRenderChildrenTask renders children to FB mRenderTargetForRenderingChildren
53 // mHorizBlurTask renders mImageActorHorizBlur Actor showing FB mRenderTargetForRenderingChildren into FB mRenderTarget2
54 // mVertBlurTask renders mImageActorVertBlur Actor showing FB mRenderTarget2 into FB mRenderTarget1
55 // mCompositeTask renders mImageActorComposite Actor showing FB mRenderTarget1 into FB mRenderTargetForRenderingChildren
57 // 2nd mode, an image is blurred and rendered to a supplied target framebuffer
58 // mHorizBlurTask renders mImageActorHorizBlur Actor showing mUserInputImage into FB mRenderTarget2
59 // mVertBlurTask renders mImageActorVertBlur Actor showing mRenderTarget2 into FB mUserOutputRenderTarget
61 // Only this 2nd mode handles ActivateOnce
79 return Toolkit::GaussianBlurView::New();
82 TypeRegistration mType( typeid(Toolkit::GaussianBlurView), typeid(Toolkit::Control), Create );
85 const unsigned int GAUSSIAN_BLUR_VIEW_DEFAULT_NUM_SAMPLES = 5;
86 const float GAUSSIAN_BLUR_VIEW_DEFAULT_BLUR_BELL_CURVE_WIDTH = 1.5f;
87 const Pixel::Format GAUSSIAN_BLUR_VIEW_DEFAULT_RENDER_TARGET_PIXEL_FORMAT = Pixel::RGBA8888;
88 const float GAUSSIAN_BLUR_VIEW_DEFAULT_BLUR_STRENGTH = 1.0f; // default, fully blurred
89 const std::string GAUSSIAN_BLUR_VIEW_STRENGTH_PROPERTY_NAME("GaussianBlurStrengthPropertyName");
90 const float GAUSSIAN_BLUR_VIEW_DEFAULT_DOWNSAMPLE_WIDTH_SCALE = 0.5f;
91 const float GAUSSIAN_BLUR_VIEW_DEFAULT_DOWNSAMPLE_HEIGHT_SCALE = 0.5f;
93 const float ARBITRARY_FIELD_OF_VIEW = Math::PI / 4.0f;
95 const char* const GAUSSIAN_BLUR_FRAGMENT_SOURCE =
96 "uniform vec2 uSampleOffsets[NUM_SAMPLES];\n"
97 "uniform float uSampleWeights[NUM_SAMPLES];\n"
101 " mediump vec4 col;\n"
102 " col = texture2D(sTexture, vec2(vTexCoord.x, vTexCoord.y) + uSampleOffsets[0]) * uSampleWeights[0]; \n"
103 " for (int i=1; i<NUM_SAMPLES; ++i) \n"
105 " col += texture2D(sTexture, vec2(vTexCoord.x, vTexCoord.y) + uSampleOffsets[i]) * uSampleWeights[i]; \n"
107 " gl_FragColor = col;\n"
113 GaussianBlurView::GaussianBlurView()
114 : Control( CONTROL_BEHAVIOUR_NONE )
115 , mNumSamples(GAUSSIAN_BLUR_VIEW_DEFAULT_NUM_SAMPLES)
116 , mPixelFormat(GAUSSIAN_BLUR_VIEW_DEFAULT_RENDER_TARGET_PIXEL_FORMAT)
117 , mDownsampleWidthScale(GAUSSIAN_BLUR_VIEW_DEFAULT_DOWNSAMPLE_WIDTH_SCALE)
118 , mDownsampleHeightScale(GAUSSIAN_BLUR_VIEW_DEFAULT_DOWNSAMPLE_HEIGHT_SCALE)
119 , mDownsampledWidth( 0.0f )
120 , mDownsampledHeight( 0.0f )
121 , mBlurUserImage( false )
122 , mBackgroundColor( Color::BLACK )
123 , mTargetSize(Vector2::ZERO)
124 , mLastSize(Vector2::ZERO)
125 , mChildrenRoot(Actor::New())
126 , mBlurStrengthPropertyIndex(Property::INVALID_INDEX)
128 SetBlurBellCurveWidth(GAUSSIAN_BLUR_VIEW_DEFAULT_BLUR_BELL_CURVE_WIDTH);
131 GaussianBlurView::GaussianBlurView( const unsigned int numSamples, const float blurBellCurveWidth, const Pixel::Format renderTargetPixelFormat,
132 const float downsampleWidthScale, const float downsampleHeightScale,
134 : Control( CONTROL_BEHAVIOUR_NONE )
135 , mNumSamples(numSamples)
136 , mPixelFormat(renderTargetPixelFormat)
137 , mDownsampleWidthScale(downsampleWidthScale)
138 , mDownsampleHeightScale(downsampleHeightScale)
139 , mDownsampledWidth( 0.0f )
140 , mDownsampledHeight( 0.0f )
141 , mBlurUserImage( blurUserImage )
142 , mBackgroundColor( Color::BLACK )
143 , mTargetSize(Vector2::ZERO)
144 , mLastSize(Vector2::ZERO)
145 , mChildrenRoot(Actor::New())
146 , mBlurStrengthPropertyIndex(Property::INVALID_INDEX)
148 SetBlurBellCurveWidth(blurBellCurveWidth);
151 GaussianBlurView::~GaussianBlurView()
156 Toolkit::GaussianBlurView GaussianBlurView::New()
158 GaussianBlurView* impl = new GaussianBlurView();
160 Dali::Toolkit::GaussianBlurView handle = Dali::Toolkit::GaussianBlurView( *impl );
162 // Second-phase init of the implementation
163 // This can only be done after the CustomActor connection has been made...
169 Toolkit::GaussianBlurView GaussianBlurView::New(const unsigned int numSamples, const float blurBellCurveWidth, const Pixel::Format renderTargetPixelFormat,
170 const float downsampleWidthScale, const float downsampleHeightScale,
173 GaussianBlurView* impl = new GaussianBlurView( numSamples, blurBellCurveWidth, renderTargetPixelFormat,
174 downsampleWidthScale, downsampleHeightScale,
177 Dali::Toolkit::GaussianBlurView handle = Dali::Toolkit::GaussianBlurView( *impl );
179 // Second-phase init of the implementation
180 // This can only be done after the CustomActor connection has been made...
186 /////////////////////////////////////////////////////////////
187 // 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
188 // 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.
189 void GaussianBlurView::Add(Actor child)
191 mChildrenRoot.Add(child);
194 void GaussianBlurView::Remove(Actor child)
196 mChildrenRoot.Remove(child);
199 void GaussianBlurView::SetUserImageAndOutputRenderTarget(Image inputImage, FrameBufferImage outputRenderTarget)
201 // can only do this if the GaussianBlurView object was created with this parameter set
202 DALI_ASSERT_ALWAYS(mBlurUserImage);
204 mUserInputImage = inputImage;
205 mImageActorHorizBlur.SetImage( mUserInputImage );
207 mUserOutputRenderTarget = outputRenderTarget;
210 FrameBufferImage GaussianBlurView::GetBlurredRenderTarget() const
212 if(!mUserOutputRenderTarget)
214 return mRenderTargetForRenderingChildren;
217 return mUserOutputRenderTarget;
220 void GaussianBlurView::SetBackgroundColor( const Vector4& color )
222 mBackgroundColor = color;
225 Vector4 GaussianBlurView::GetBackgroundColor() const
227 return mBackgroundColor;
230 ///////////////////////////////////////////////////////////
236 * EqualToConstraintFloat
238 * f(current, property) = property
240 struct EqualToConstraintFloat
242 EqualToConstraintFloat(){}
244 float operator()(const float current, const PropertyInput& property) {return property.GetFloat();}
247 void GaussianBlurView::OnInitialize()
249 // root actor to parent all user added actors, needed to allow us to set that subtree as exclusive for our child render task
250 mChildrenRoot.SetParentOrigin(ParentOrigin::CENTER);
251 mChildrenRoot.ApplyConstraint( Constraint::New<Vector3>( Actor::SIZE, ParentSource( Actor::SIZE ), EqualToConstraint() ) ); // same size as GaussianBlurView object
254 //////////////////////////////////////////////////////
258 std::ostringstream horizFragmentShaderStringStream;
259 horizFragmentShaderStringStream << "#define NUM_SAMPLES " << mNumSamples << "\n";
260 horizFragmentShaderStringStream << GAUSSIAN_BLUR_FRAGMENT_SOURCE;
261 mHorizBlurShader = ShaderEffect::New( "", horizFragmentShaderStringStream.str() );
263 std::ostringstream vertFragmentShaderStringStream;
264 vertFragmentShaderStringStream << "#define NUM_SAMPLES " << mNumSamples << "\n";
265 vertFragmentShaderStringStream << GAUSSIAN_BLUR_FRAGMENT_SOURCE;
266 mVertBlurShader = ShaderEffect::New( "", vertFragmentShaderStringStream.str() );
269 //////////////////////////////////////////////////////
272 // Create an ImageActor for performing a horizontal blur on the texture
273 mImageActorHorizBlur = ImageActor::New();
274 mImageActorHorizBlur.SetParentOrigin(ParentOrigin::CENTER);
275 mImageActorHorizBlur.ScaleBy( Vector3(1.0f, -1.0f, 1.0f) ); // FIXME
276 mImageActorHorizBlur.SetShaderEffect( mHorizBlurShader );
278 // Create an ImageActor for performing a vertical blur on the texture
279 mImageActorVertBlur = ImageActor::New();
280 mImageActorVertBlur.SetParentOrigin(ParentOrigin::CENTER);
281 mImageActorVertBlur.ScaleBy( Vector3(1.0f, -1.0f, 1.0f) ); // FIXME
282 mImageActorVertBlur.SetShaderEffect( mVertBlurShader );
284 // Register a property that the user can control to fade the blur in / out via the GaussianBlurView object
285 mBlurStrengthPropertyIndex = Self().RegisterProperty(GAUSSIAN_BLUR_VIEW_STRENGTH_PROPERTY_NAME, GAUSSIAN_BLUR_VIEW_DEFAULT_BLUR_STRENGTH);
287 // Create an ImageActor for compositing the blur and the original child actors render
290 mImageActorComposite = ImageActor::New();
291 mImageActorComposite.SetParentOrigin(ParentOrigin::CENTER);
292 mImageActorComposite.ApplyConstraint( Constraint::New<Vector3>( Actor::SIZE, ParentSource( Actor::SIZE ), EqualToConstraint() ) ); // same size as GaussianBlurView object
293 mImageActorComposite.ScaleBy( Vector3(1.0f, -1.0f, 1.0f) ); // FIXME
294 mImageActorComposite.SetOpacity(GAUSSIAN_BLUR_VIEW_DEFAULT_BLUR_STRENGTH); // ensure alpha is enabled for this object and set default value
296 Constraint blurStrengthConstraint = Constraint::New<float>( Actor::COLOR_ALPHA, ParentSource(mBlurStrengthPropertyIndex), EqualToConstraintFloat());
297 mImageActorComposite.ApplyConstraint(blurStrengthConstraint);
299 // Create an ImageActor for holding final result, i.e. the blurred image. This will get rendered to screen later, via default / user render task
300 mTargetActor = ImageActor::New();
301 mTargetActor.SetParentOrigin(ParentOrigin::CENTER);
302 mTargetActor.ApplyConstraint( Constraint::New<Vector3>( Actor::SIZE, ParentSource( Actor::SIZE ), EqualToConstraint() ) ); // same size as GaussianBlurView object
303 mTargetActor.ScaleBy( Vector3(1.0f, -1.0f, 1.0f) ); // FIXME
306 //////////////////////////////////////////////////////
307 // Create cameras for the renders corresponding to the view size
308 mRenderFullSizeCamera = CameraActor::New();
309 mRenderFullSizeCamera.SetParentOrigin(ParentOrigin::CENTER);
312 //////////////////////////////////////////////////////
313 // Connect to actor tree
314 Self().Add( mImageActorComposite );
315 Self().Add( mTargetActor );
316 Self().Add( mRenderFullSizeCamera );
320 //////////////////////////////////////////////////////
321 // Create camera for the renders corresponding to the (potentially downsampled) render targets' size
322 mRenderDownsampledCamera = CameraActor::New();
323 mRenderDownsampledCamera.SetParentOrigin(ParentOrigin::CENTER);
326 //////////////////////////////////////////////////////
327 // Connect to actor tree
328 Self().Add( mChildrenRoot );
329 Self().Add( mImageActorHorizBlur );
330 Self().Add( mImageActorVertBlur );
331 Self().Add( mRenderDownsampledCamera );
336 * ZrelativeToYconstraint
338 * f(current, property, scale) = Vector3(current.x, current.y, property.y * scale)
340 struct ZrelativeToYconstraint
342 ZrelativeToYconstraint( float scale )
346 Vector3 operator()(const Vector3& current,
347 const PropertyInput& property)
353 v.z = property.GetVector3().y * mScale;
361 void GaussianBlurView::OnControlSizeSet(const Vector3& targetSize)
363 mTargetSize = Vector2(targetSize);
365 // if we are already on stage, need to update render target sizes now to reflect the new size of this actor
372 void GaussianBlurView::AllocateResources()
374 // size of render targets etc is based on the size of this actor, ignoring z
375 if(mTargetSize != mLastSize)
377 mLastSize = mTargetSize;
379 // get size of downsampled render targets
380 mDownsampledWidth = mTargetSize.width * mDownsampleWidthScale;
381 mDownsampledHeight = mTargetSize.height * mDownsampleHeightScale;
383 // Create and place a camera for the renders corresponding to the (potentially downsampled) render targets' size
384 mRenderDownsampledCamera.SetFieldOfView(ARBITRARY_FIELD_OF_VIEW);
385 // 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
386 mRenderDownsampledCamera.SetNearClippingPlane(1.0f);
387 mRenderDownsampledCamera.SetAspectRatio(mDownsampledWidth / mDownsampledHeight);
388 mRenderDownsampledCamera.SetType(Dali::Camera::FREE_LOOK); // camera orientation based solely on actor
389 // Point the camera back into the scene
390 mRenderDownsampledCamera.SetRotation(Quaternion(M_PI, Vector3::YAXIS));
392 mRenderDownsampledCamera.SetPosition(0.0f, 0.0f, ((mDownsampledHeight * 0.5f) / tanf(ARBITRARY_FIELD_OF_VIEW * 0.5f)));
394 // setup for normal operation
397 // Create and place a camera for the children render, corresponding to its render target size
398 mRenderFullSizeCamera.SetFieldOfView(ARBITRARY_FIELD_OF_VIEW);
399 // 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
400 mRenderFullSizeCamera.SetNearClippingPlane(1.0f);
401 mRenderFullSizeCamera.SetAspectRatio(mTargetSize.width / mTargetSize.height);
402 mRenderFullSizeCamera.SetType(Dali::Camera::FREE_LOOK); // camera orientation based solely on actor
403 // Point the camera back into the scene
404 mRenderFullSizeCamera.SetRotation(Quaternion(M_PI, Vector3::YAXIS));
406 float cameraPosConstraintScale = 0.5f / tanf(ARBITRARY_FIELD_OF_VIEW * 0.5f);
407 mRenderFullSizeCamera.SetPosition(0.0f, 0.0f, mTargetSize.height * cameraPosConstraintScale);
409 // 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
410 // 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
411 // size, this is the trade off for not being able to modify render target size
412 // Change camera z position based on GaussianBlurView actor height
413 mRenderFullSizeCamera.RemoveConstraints();
414 mRenderFullSizeCamera.ApplyConstraint( Constraint::New<Vector3>( Actor::POSITION, ParentSource( Actor::SIZE ), ZrelativeToYconstraint(cameraPosConstraintScale) ) );
416 // create offscreen buffer of new size to render our child actors to
417 mRenderTargetForRenderingChildren = FrameBufferImage::New( mTargetSize.width, mTargetSize.height, mPixelFormat, Dali::Image::Unused );
419 // Set ImageActor for performing a horizontal blur on the texture
420 mImageActorHorizBlur.SetImage( mRenderTargetForRenderingChildren );
422 // Create offscreen buffer for vert blur pass
423 mRenderTarget1 = FrameBufferImage::New( mDownsampledWidth, mDownsampledHeight, mPixelFormat, Dali::Image::Unused );
425 // use the completed blur in the first buffer and composite with the original child actors render
426 mImageActorComposite.SetImage( mRenderTarget1 );
428 // set up target actor for rendering result, i.e. the blurred image
429 mTargetActor.SetImage(mRenderTargetForRenderingChildren);
432 // Create offscreen buffer for horiz blur pass
433 mRenderTarget2 = FrameBufferImage::New( mDownsampledWidth, mDownsampledHeight, mPixelFormat, Dali::Image::Unused );
435 // size needs to match render target
436 mImageActorHorizBlur.SetSize(mDownsampledWidth, mDownsampledHeight);
438 // size needs to match render target
439 mImageActorVertBlur.SetImage( mRenderTarget2 );
440 mImageActorVertBlur.SetSize(mDownsampledWidth, mDownsampledHeight);
442 // set gaussian blur up for new sized render targets
443 SetShaderConstants();
447 void GaussianBlurView::CreateRenderTasks()
449 RenderTaskList taskList = Stage::GetCurrent().GetRenderTaskList();
453 // create render task to render our child actors to offscreen buffer
454 mRenderChildrenTask = taskList.CreateTask();
455 mRenderChildrenTask.SetSourceActor( mChildrenRoot );
456 mRenderChildrenTask.SetExclusive(true);
457 mRenderChildrenTask.SetInputEnabled( false );
458 mRenderChildrenTask.SetClearEnabled( true );
459 mRenderChildrenTask.SetClearColor( mBackgroundColor );
461 mRenderChildrenTask.SetCameraActor(mRenderFullSizeCamera);
462 mRenderChildrenTask.SetTargetFrameBuffer( mRenderTargetForRenderingChildren );
465 // perform a horizontal blur targeting the second buffer
466 mHorizBlurTask = taskList.CreateTask();
467 mHorizBlurTask.SetSourceActor( mImageActorHorizBlur );
468 mHorizBlurTask.SetExclusive(true);
469 mHorizBlurTask.SetInputEnabled( false );
470 mHorizBlurTask.SetClearEnabled( true );
471 mHorizBlurTask.SetClearColor( mBackgroundColor );
472 if( mRenderOnce && mBlurUserImage )
474 mHorizBlurTask.SetRefreshRate(RenderTask::REFRESH_ONCE);
477 // use the second buffer and perform a horizontal blur targeting the first buffer
478 mVertBlurTask = taskList.CreateTask();
479 mVertBlurTask.SetSourceActor( mImageActorVertBlur );
480 mVertBlurTask.SetExclusive(true);
481 mVertBlurTask.SetInputEnabled( false );
482 mVertBlurTask.SetClearEnabled( true );
483 mVertBlurTask.SetClearColor( mBackgroundColor );
484 if( mRenderOnce && mBlurUserImage )
486 mVertBlurTask.SetRefreshRate(RenderTask::REFRESH_ONCE);
487 mVertBlurTask.FinishedSignal().Connect( this, &GaussianBlurView::OnRenderTaskFinished );
490 // use the completed blur in the first buffer and composite with the original child actors render
493 mCompositeTask = taskList.CreateTask();
494 mCompositeTask.SetSourceActor( mImageActorComposite );
495 mCompositeTask.SetExclusive(true);
496 mCompositeTask.SetInputEnabled( false );
498 mCompositeTask.SetCameraActor(mRenderFullSizeCamera);
499 mCompositeTask.SetTargetFrameBuffer( mRenderTargetForRenderingChildren );
502 mHorizBlurTask.SetCameraActor(mRenderDownsampledCamera);
503 mVertBlurTask.SetCameraActor(mRenderDownsampledCamera);
505 mHorizBlurTask.SetTargetFrameBuffer( mRenderTarget2 );
506 if(mUserOutputRenderTarget)
508 mVertBlurTask.SetTargetFrameBuffer( mUserOutputRenderTarget );
512 mVertBlurTask.SetTargetFrameBuffer( mRenderTarget1 );
516 void GaussianBlurView::RemoveRenderTasks()
518 RenderTaskList taskList = Stage::GetCurrent().GetRenderTaskList();
520 taskList.RemoveTask(mRenderChildrenTask);
521 taskList.RemoveTask(mHorizBlurTask);
522 taskList.RemoveTask(mVertBlurTask);
523 taskList.RemoveTask(mCompositeTask);
526 void GaussianBlurView::OnStageDisconnection()
528 // TODO: can't call this here, since SetImage() calls fails similarly to above
529 // Need to fix the stage connection so this callback can be used arbitrarily. At that point we can simplify the API by removing the need for Activate() / Deactivate()
533 void GaussianBlurView::OnControlStageConnection()
535 // TODO: can't call this here, since SetImage() calls fail to connect images to stage, since parent chain not fully on stage yet
536 // Need to fix the stage connection so this callback can be used arbitrarily. At that point we can simplify the API by removing the need for Activate() / Deactivate()
540 void GaussianBlurView::Activate()
542 // make sure resources are allocated and start the render tasks processing
547 void GaussianBlurView::ActivateOnce()
549 DALI_ASSERT_ALWAYS(mBlurUserImage); // Only works with blurring image mode.
554 void GaussianBlurView::Deactivate()
556 // stop render tasks processing
557 // Note: render target resources are automatically freed since we set the Image::Unused flag
562 void GaussianBlurView::SetBlurBellCurveWidth(float blurBellCurveWidth)
564 // a value of zero leads to undefined Gaussian weights, do not allow user to do this
565 mBlurBellCurveWidth = std::max( blurBellCurveWidth, 0.001f );
568 float GaussianBlurView::CalcGaussianWeight(float x)
570 return (1.0f / sqrt(2.0f * Math::PI * mBlurBellCurveWidth)) * exp(-(x * x) / (2.0f * mBlurBellCurveWidth * mBlurBellCurveWidth));
573 void GaussianBlurView::SetShaderConstants()
578 float w, totalWeights;
581 uvOffsets = new Vector2[mNumSamples + 1];
582 weights = new float[mNumSamples + 1];
584 totalWeights = weights[0] = CalcGaussianWeight(0);
585 uvOffsets[0].x = 0.0f;
586 uvOffsets[0].y = 0.0f;
588 for(i=0; i<mNumSamples >> 1; i++)
590 w = CalcGaussianWeight((float)(i + 1));
591 weights[(i << 1) + 1] = w;
592 weights[(i << 1) + 2] = w;
593 totalWeights += w * 2.0f;
595 // offset texture lookup to between texels, that way the bilinear filter in the texture hardware will average two samples with one lookup
596 ofs = ((float)(i << 1)) + 1.5f;
598 // get offsets from units of pixels into uv coordinates in [0..1]
599 float ofsX = ofs / mDownsampledWidth;
600 float ofsY = ofs / mDownsampledHeight;
601 uvOffsets[(i << 1) + 1].x = ofsX;
602 uvOffsets[(i << 1) + 1].y = ofsY;
604 uvOffsets[(i << 1) + 2].x = -ofsX;
605 uvOffsets[(i << 1) + 2].y = -ofsY;
608 for(i=0; i<mNumSamples; i++)
610 weights[i] /= totalWeights;
613 // set shader constants
614 Vector2 xAxis(1.0f, 0.0f);
615 Vector2 yAxis(0.0f, 1.0f);
616 for (i = 0; i < mNumSamples; ++i )
618 mHorizBlurShader.SetUniform( GetSampleOffsetsPropertyName( i ), uvOffsets[ i ] * xAxis );
619 mHorizBlurShader.SetUniform( GetSampleWeightsPropertyName( i ), weights[ i ] );
621 mVertBlurShader.SetUniform( GetSampleOffsetsPropertyName( i ), uvOffsets[ i ] * yAxis );
622 mVertBlurShader.SetUniform( GetSampleWeightsPropertyName( i ), weights[ i ] );
629 std::string GaussianBlurView::GetSampleOffsetsPropertyName( unsigned int index ) const
631 DALI_ASSERT_ALWAYS( index < mNumSamples );
633 std::ostringstream oss;
634 oss << "uSampleOffsets[" << index << "]";
638 std::string GaussianBlurView::GetSampleWeightsPropertyName( unsigned int index ) const
640 DALI_ASSERT_ALWAYS( index < mNumSamples );
642 std::ostringstream oss;
643 oss << "uSampleWeights[" << index << "]";
647 Dali::Toolkit::GaussianBlurView::GaussianBlurViewSignal& GaussianBlurView::FinishedSignal()
649 return mFinishedSignal;
652 void GaussianBlurView::OnRenderTaskFinished(Dali::RenderTask& renderTask)
654 Toolkit::GaussianBlurView handle( GetOwner() );
655 mFinishedSignal.Emit( handle );
658 } // namespace Internal
659 } // namespace Toolkit