2 * Copyright (c) 2014 Samsung Electronics Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 #include "gaussian-blur-view-impl.h"
24 #include <dali/public-api/animation/active-constraint.h>
25 #include <dali/public-api/animation/constraint.h>
26 #include <dali/public-api/animation/constraints.h>
27 #include <dali/public-api/common/stage.h>
28 #include <dali/public-api/object/type-registry.h>
29 #include <dali/public-api/render-tasks/render-task-list.h>
30 #include <dali/integration-api/debug.h>
33 #include <dali-toolkit/public-api/controls/gaussian-blur-view/gaussian-blur-view.h>
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 // mChildrenRoot Add()/Remove() overloads - better solution
40 // Manager object - re-use render targets if there are multiple GaussianBlurViews created
44 /////////////////////////////////////////////////////////
45 // IMPLEMENTATION NOTES
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.
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
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
67 // Only this 2nd mode handles ActivateOnce
85 return Toolkit::GaussianBlurView::New();
88 TypeRegistration mType( typeid(Toolkit::GaussianBlurView), typeid(Toolkit::Control), Create );
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 std::string 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;
99 const float ARBITRARY_FIELD_OF_VIEW = Math::PI / 4.0f;
101 const char* const GAUSSIAN_BLUR_FRAGMENT_SOURCE =
102 "uniform mediump vec2 uSampleOffsets[NUM_SAMPLES];\n"
103 "uniform mediump float uSampleWeights[NUM_SAMPLES];\n"
107 " mediump vec4 col;\n"
108 " col = texture2D(sTexture, vec2(vTexCoord.x, vTexCoord.y) + uSampleOffsets[0]) * uSampleWeights[0]; \n"
109 " for (int i=1; i<NUM_SAMPLES; ++i) \n"
111 " col += texture2D(sTexture, vec2(vTexCoord.x, vTexCoord.y) + uSampleOffsets[i]) * uSampleWeights[i]; \n"
113 " gl_FragColor = col;\n"
119 GaussianBlurView::GaussianBlurView()
120 : Control( CONTROL_BEHAVIOUR_NONE )
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 , mBlurStrengthPropertyIndex(Property::INVALID_INDEX)
136 SetBlurBellCurveWidth(GAUSSIAN_BLUR_VIEW_DEFAULT_BLUR_BELL_CURVE_WIDTH);
139 GaussianBlurView::GaussianBlurView( const unsigned int numSamples, const float blurBellCurveWidth, const Pixel::Format renderTargetPixelFormat,
140 const float downsampleWidthScale, const float downsampleHeightScale,
142 : Control( CONTROL_BEHAVIOUR_NONE )
143 , mNumSamples(numSamples)
144 , mBlurBellCurveWidth( 0.001f )
145 , mPixelFormat(renderTargetPixelFormat)
146 , mDownsampleWidthScale(downsampleWidthScale)
147 , mDownsampleHeightScale(downsampleHeightScale)
148 , mDownsampledWidth( 0.0f )
149 , mDownsampledHeight( 0.0f )
150 , mBlurUserImage( blurUserImage )
151 , mRenderOnce( false )
152 , mBackgroundColor( Color::BLACK )
153 , mTargetSize(Vector2::ZERO)
154 , mLastSize(Vector2::ZERO)
155 , mChildrenRoot(Actor::New())
156 , mBlurStrengthPropertyIndex(Property::INVALID_INDEX)
158 SetBlurBellCurveWidth(blurBellCurveWidth);
161 GaussianBlurView::~GaussianBlurView()
166 Toolkit::GaussianBlurView GaussianBlurView::New()
168 GaussianBlurView* impl = new GaussianBlurView();
170 Dali::Toolkit::GaussianBlurView handle = Dali::Toolkit::GaussianBlurView( *impl );
172 // Second-phase init of the implementation
173 // This can only be done after the CustomActor connection has been made...
179 Toolkit::GaussianBlurView GaussianBlurView::New(const unsigned int numSamples, const float blurBellCurveWidth, const Pixel::Format renderTargetPixelFormat,
180 const float downsampleWidthScale, const float downsampleHeightScale,
183 GaussianBlurView* impl = new GaussianBlurView( numSamples, blurBellCurveWidth, renderTargetPixelFormat,
184 downsampleWidthScale, downsampleHeightScale,
187 Dali::Toolkit::GaussianBlurView handle = Dali::Toolkit::GaussianBlurView( *impl );
189 // Second-phase init of the implementation
190 // This can only be done after the CustomActor connection has been made...
196 /////////////////////////////////////////////////////////////
197 // 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
198 // 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.
199 void GaussianBlurView::Add(Actor child)
201 mChildrenRoot.Add(child);
204 void GaussianBlurView::Remove(Actor child)
206 mChildrenRoot.Remove(child);
209 void GaussianBlurView::SetUserImageAndOutputRenderTarget(Image inputImage, FrameBufferImage outputRenderTarget)
211 // can only do this if the GaussianBlurView object was created with this parameter set
212 DALI_ASSERT_ALWAYS(mBlurUserImage);
214 mUserInputImage = inputImage;
215 mImageActorHorizBlur.SetImage( mUserInputImage );
217 mUserOutputRenderTarget = outputRenderTarget;
220 FrameBufferImage GaussianBlurView::GetBlurredRenderTarget() const
222 if(!mUserOutputRenderTarget)
224 return mRenderTargetForRenderingChildren;
227 return mUserOutputRenderTarget;
230 void GaussianBlurView::SetBackgroundColor( const Vector4& color )
232 mBackgroundColor = color;
235 Vector4 GaussianBlurView::GetBackgroundColor() const
237 return mBackgroundColor;
240 ///////////////////////////////////////////////////////////
246 * EqualToConstraintFloat
248 * f(current, property) = property
250 struct EqualToConstraintFloat
252 EqualToConstraintFloat(){}
254 float operator()(const float current, const PropertyInput& property) {return property.GetFloat();}
257 void GaussianBlurView::OnInitialize()
259 // root actor to parent all user added actors, needed to allow us to set that subtree as exclusive for our child render task
260 mChildrenRoot.SetParentOrigin(ParentOrigin::CENTER);
262 //////////////////////////////////////////////////////
266 std::ostringstream horizFragmentShaderStringStream;
267 horizFragmentShaderStringStream << "#define NUM_SAMPLES " << mNumSamples << "\n";
268 horizFragmentShaderStringStream << GAUSSIAN_BLUR_FRAGMENT_SOURCE;
269 mHorizBlurShader = ShaderEffect::New( "", horizFragmentShaderStringStream.str() );
271 std::ostringstream vertFragmentShaderStringStream;
272 vertFragmentShaderStringStream << "#define NUM_SAMPLES " << mNumSamples << "\n";
273 vertFragmentShaderStringStream << GAUSSIAN_BLUR_FRAGMENT_SOURCE;
274 mVertBlurShader = ShaderEffect::New( "", vertFragmentShaderStringStream.str() );
277 //////////////////////////////////////////////////////
280 // Create an ImageActor for performing a horizontal blur on the texture
281 mImageActorHorizBlur = ImageActor::New();
282 mImageActorHorizBlur.SetParentOrigin(ParentOrigin::CENTER);
283 mImageActorHorizBlur.ScaleBy( Vector3(1.0f, -1.0f, 1.0f) ); // FIXME
284 mImageActorHorizBlur.SetShaderEffect( mHorizBlurShader );
286 // Create an ImageActor for performing a vertical blur on the texture
287 mImageActorVertBlur = ImageActor::New();
288 mImageActorVertBlur.SetParentOrigin(ParentOrigin::CENTER);
289 mImageActorVertBlur.ScaleBy( Vector3(1.0f, -1.0f, 1.0f) ); // FIXME
290 mImageActorVertBlur.SetShaderEffect( mVertBlurShader );
292 // Register a property that the user can control to fade the blur in / out via the GaussianBlurView object
293 mBlurStrengthPropertyIndex = Self().RegisterProperty(GAUSSIAN_BLUR_VIEW_STRENGTH_PROPERTY_NAME, GAUSSIAN_BLUR_VIEW_DEFAULT_BLUR_STRENGTH);
295 // Create an ImageActor for compositing the blur and the original child actors render
298 mImageActorComposite = ImageActor::New();
299 mImageActorComposite.SetParentOrigin(ParentOrigin::CENTER);
300 mImageActorComposite.ScaleBy( Vector3(1.0f, -1.0f, 1.0f) ); // FIXME
301 mImageActorComposite.SetOpacity(GAUSSIAN_BLUR_VIEW_DEFAULT_BLUR_STRENGTH); // ensure alpha is enabled for this object and set default value
303 Constraint blurStrengthConstraint = Constraint::New<float>( Actor::Property::ColorAlpha, ParentSource(mBlurStrengthPropertyIndex), EqualToConstraintFloat());
304 mImageActorComposite.ApplyConstraint(blurStrengthConstraint);
306 // Create an ImageActor for holding final result, i.e. the blurred image. This will get rendered to screen later, via default / user render task
307 mTargetActor = ImageActor::New();
308 mTargetActor.SetParentOrigin(ParentOrigin::CENTER);
309 mTargetActor.ScaleBy( Vector3(1.0f, -1.0f, 1.0f) ); // FIXME
312 //////////////////////////////////////////////////////
313 // Create cameras for the renders corresponding to the view size
314 mRenderFullSizeCamera = CameraActor::New();
315 mRenderFullSizeCamera.SetParentOrigin(ParentOrigin::CENTER);
318 //////////////////////////////////////////////////////
319 // Connect to actor tree
320 Self().Add( mImageActorComposite );
321 Self().Add( mTargetActor );
322 Self().Add( mRenderFullSizeCamera );
326 //////////////////////////////////////////////////////
327 // Create camera for the renders corresponding to the (potentially downsampled) render targets' size
328 mRenderDownsampledCamera = CameraActor::New();
329 mRenderDownsampledCamera.SetParentOrigin(ParentOrigin::CENTER);
332 //////////////////////////////////////////////////////
333 // Connect to actor tree
334 Self().Add( mChildrenRoot );
335 Self().Add( mImageActorHorizBlur );
336 Self().Add( mImageActorVertBlur );
337 Self().Add( mRenderDownsampledCamera );
342 * ZrelativeToYconstraint
344 * f(current, property, scale) = Vector3(current.x, current.y, property.y * scale)
346 struct ZrelativeToYconstraint
348 ZrelativeToYconstraint( float scale )
352 Vector3 operator()(const Vector3& current,
353 const PropertyInput& property)
359 v.z = property.GetVector3().y * mScale;
367 void GaussianBlurView::OnControlSizeSet(const Vector3& targetSize)
369 mTargetSize = Vector2(targetSize);
371 mChildrenRoot.SetSize(targetSize);
373 if( !mBlurUserImage )
375 mImageActorComposite.SetSize(targetSize);
376 mTargetActor.SetSize(targetSize);
378 // 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
379 // 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
380 // size, this is the trade off for not being able to modify render target size
381 // Change camera z position based on GaussianBlurView actor height
382 float cameraPosConstraintScale = 0.5f / tanf(ARBITRARY_FIELD_OF_VIEW * 0.5f);
383 mRenderFullSizeCamera.SetZ(mTargetSize.height * cameraPosConstraintScale);
387 // if we are already on stage, need to update render target sizes now to reflect the new size of this actor
394 void GaussianBlurView::AllocateResources()
396 // size of render targets etc is based on the size of this actor, ignoring z
397 if(mTargetSize != mLastSize)
399 mLastSize = mTargetSize;
401 // get size of downsampled render targets
402 mDownsampledWidth = mTargetSize.width * mDownsampleWidthScale;
403 mDownsampledHeight = mTargetSize.height * mDownsampleHeightScale;
405 // Create and place a camera for the renders corresponding to the (potentially downsampled) render targets' size
406 mRenderDownsampledCamera.SetFieldOfView(ARBITRARY_FIELD_OF_VIEW);
407 // 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
408 mRenderDownsampledCamera.SetNearClippingPlane(1.0f);
409 mRenderDownsampledCamera.SetAspectRatio(mDownsampledWidth / mDownsampledHeight);
410 mRenderDownsampledCamera.SetType(Dali::Camera::FREE_LOOK); // camera orientation based solely on actor
411 // Point the camera back into the scene
412 mRenderDownsampledCamera.SetRotation(Quaternion(M_PI, Vector3::YAXIS));
414 mRenderDownsampledCamera.SetPosition(0.0f, 0.0f, ((mDownsampledHeight * 0.5f) / tanf(ARBITRARY_FIELD_OF_VIEW * 0.5f)));
416 // setup for normal operation
419 // Create and place a camera for the children render, corresponding to its render target size
420 mRenderFullSizeCamera.SetFieldOfView(ARBITRARY_FIELD_OF_VIEW);
421 // 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
422 mRenderFullSizeCamera.SetNearClippingPlane(1.0f);
423 mRenderFullSizeCamera.SetAspectRatio(mTargetSize.width / mTargetSize.height);
424 mRenderFullSizeCamera.SetType(Dali::Camera::FREE_LOOK); // camera orientation based solely on actor
425 // Point the camera back into the scene
426 mRenderFullSizeCamera.SetRotation(Quaternion(M_PI, Vector3::YAXIS));
428 float cameraPosConstraintScale = 0.5f / tanf(ARBITRARY_FIELD_OF_VIEW * 0.5f);
429 mRenderFullSizeCamera.SetPosition(0.0f, 0.0f, mTargetSize.height * cameraPosConstraintScale);
431 // create offscreen buffer of new size to render our child actors to
432 mRenderTargetForRenderingChildren = FrameBufferImage::New( mTargetSize.width, mTargetSize.height, mPixelFormat, Dali::Image::UNUSED );
434 // Set ImageActor for performing a horizontal blur on the texture
435 mImageActorHorizBlur.SetImage( mRenderTargetForRenderingChildren );
437 // Create offscreen buffer for vert blur pass
438 mRenderTarget1 = FrameBufferImage::New( mDownsampledWidth, mDownsampledHeight, mPixelFormat, Dali::Image::UNUSED );
440 // use the completed blur in the first buffer and composite with the original child actors render
441 mImageActorComposite.SetImage( mRenderTarget1 );
443 // set up target actor for rendering result, i.e. the blurred image
444 mTargetActor.SetImage(mRenderTargetForRenderingChildren);
447 // Create offscreen buffer for horiz blur pass
448 mRenderTarget2 = FrameBufferImage::New( mDownsampledWidth, mDownsampledHeight, mPixelFormat, Dali::Image::UNUSED );
450 // size needs to match render target
451 mImageActorHorizBlur.SetSize(mDownsampledWidth, mDownsampledHeight);
453 // size needs to match render target
454 mImageActorVertBlur.SetImage( mRenderTarget2 );
455 mImageActorVertBlur.SetSize(mDownsampledWidth, mDownsampledHeight);
457 // set gaussian blur up for new sized render targets
458 SetShaderConstants();
462 void GaussianBlurView::CreateRenderTasks()
464 RenderTaskList taskList = Stage::GetCurrent().GetRenderTaskList();
468 // create render task to render our child actors to offscreen buffer
469 mRenderChildrenTask = taskList.CreateTask();
470 mRenderChildrenTask.SetSourceActor( mChildrenRoot );
471 mRenderChildrenTask.SetExclusive(true);
472 mRenderChildrenTask.SetInputEnabled( false );
473 mRenderChildrenTask.SetClearEnabled( true );
474 mRenderChildrenTask.SetClearColor( mBackgroundColor );
476 mRenderChildrenTask.SetCameraActor(mRenderFullSizeCamera);
477 mRenderChildrenTask.SetTargetFrameBuffer( mRenderTargetForRenderingChildren );
480 // perform a horizontal blur targeting the second buffer
481 mHorizBlurTask = taskList.CreateTask();
482 mHorizBlurTask.SetSourceActor( mImageActorHorizBlur );
483 mHorizBlurTask.SetExclusive(true);
484 mHorizBlurTask.SetInputEnabled( false );
485 mHorizBlurTask.SetClearEnabled( true );
486 mHorizBlurTask.SetClearColor( mBackgroundColor );
487 if( mRenderOnce && mBlurUserImage )
489 mHorizBlurTask.SetRefreshRate(RenderTask::REFRESH_ONCE);
492 // use the second buffer and perform a horizontal blur targeting the first buffer
493 mVertBlurTask = taskList.CreateTask();
494 mVertBlurTask.SetSourceActor( mImageActorVertBlur );
495 mVertBlurTask.SetExclusive(true);
496 mVertBlurTask.SetInputEnabled( false );
497 mVertBlurTask.SetClearEnabled( true );
498 mVertBlurTask.SetClearColor( mBackgroundColor );
499 if( mRenderOnce && mBlurUserImage )
501 mVertBlurTask.SetRefreshRate(RenderTask::REFRESH_ONCE);
502 mVertBlurTask.FinishedSignal().Connect( this, &GaussianBlurView::OnRenderTaskFinished );
505 // use the completed blur in the first buffer and composite with the original child actors render
508 mCompositeTask = taskList.CreateTask();
509 mCompositeTask.SetSourceActor( mImageActorComposite );
510 mCompositeTask.SetExclusive(true);
511 mCompositeTask.SetInputEnabled( false );
513 mCompositeTask.SetCameraActor(mRenderFullSizeCamera);
514 mCompositeTask.SetTargetFrameBuffer( mRenderTargetForRenderingChildren );
517 mHorizBlurTask.SetCameraActor(mRenderDownsampledCamera);
518 mVertBlurTask.SetCameraActor(mRenderDownsampledCamera);
520 mHorizBlurTask.SetTargetFrameBuffer( mRenderTarget2 );
521 if(mUserOutputRenderTarget)
523 mVertBlurTask.SetTargetFrameBuffer( mUserOutputRenderTarget );
527 mVertBlurTask.SetTargetFrameBuffer( mRenderTarget1 );
531 void GaussianBlurView::RemoveRenderTasks()
533 RenderTaskList taskList = Stage::GetCurrent().GetRenderTaskList();
535 taskList.RemoveTask(mRenderChildrenTask);
536 taskList.RemoveTask(mHorizBlurTask);
537 taskList.RemoveTask(mVertBlurTask);
538 taskList.RemoveTask(mCompositeTask);
541 void GaussianBlurView::OnStageDisconnection()
543 // TODO: can't call this here, since SetImage() calls fails similarly to above
544 // 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()
548 void GaussianBlurView::OnControlStageConnection()
550 // TODO: can't call this here, since SetImage() calls fail to connect images to stage, since parent chain not fully on stage yet
551 // 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()
555 void GaussianBlurView::Activate()
557 // make sure resources are allocated and start the render tasks processing
562 void GaussianBlurView::ActivateOnce()
564 DALI_ASSERT_ALWAYS(mBlurUserImage); // Only works with blurring image mode.
569 void GaussianBlurView::Deactivate()
571 // stop render tasks processing
572 // Note: render target resources are automatically freed since we set the Image::Unused flag
577 void GaussianBlurView::SetBlurBellCurveWidth(float blurBellCurveWidth)
579 // a value of zero leads to undefined Gaussian weights, do not allow user to do this
580 mBlurBellCurveWidth = std::max( blurBellCurveWidth, 0.001f );
583 float GaussianBlurView::CalcGaussianWeight(float x)
585 return (1.0f / sqrt(2.0f * Math::PI * mBlurBellCurveWidth)) * exp(-(x * x) / (2.0f * mBlurBellCurveWidth * mBlurBellCurveWidth));
588 void GaussianBlurView::SetShaderConstants()
593 float w, totalWeights;
596 uvOffsets = new Vector2[mNumSamples + 1];
597 weights = new float[mNumSamples + 1];
599 totalWeights = weights[0] = CalcGaussianWeight(0);
600 uvOffsets[0].x = 0.0f;
601 uvOffsets[0].y = 0.0f;
603 for(i=0; i<mNumSamples >> 1; i++)
605 w = CalcGaussianWeight((float)(i + 1));
606 weights[(i << 1) + 1] = w;
607 weights[(i << 1) + 2] = w;
608 totalWeights += w * 2.0f;
610 // offset texture lookup to between texels, that way the bilinear filter in the texture hardware will average two samples with one lookup
611 ofs = ((float)(i << 1)) + 1.5f;
613 // get offsets from units of pixels into uv coordinates in [0..1]
614 float ofsX = ofs / mDownsampledWidth;
615 float ofsY = ofs / mDownsampledHeight;
616 uvOffsets[(i << 1) + 1].x = ofsX;
617 uvOffsets[(i << 1) + 1].y = ofsY;
619 uvOffsets[(i << 1) + 2].x = -ofsX;
620 uvOffsets[(i << 1) + 2].y = -ofsY;
623 for(i=0; i<mNumSamples; i++)
625 weights[i] /= totalWeights;
628 // set shader constants
629 Vector2 xAxis(1.0f, 0.0f);
630 Vector2 yAxis(0.0f, 1.0f);
631 for (i = 0; i < mNumSamples; ++i )
633 mHorizBlurShader.SetUniform( GetSampleOffsetsPropertyName( i ), uvOffsets[ i ] * xAxis );
634 mHorizBlurShader.SetUniform( GetSampleWeightsPropertyName( i ), weights[ i ] );
636 mVertBlurShader.SetUniform( GetSampleOffsetsPropertyName( i ), uvOffsets[ i ] * yAxis );
637 mVertBlurShader.SetUniform( GetSampleWeightsPropertyName( i ), weights[ i ] );
644 std::string GaussianBlurView::GetSampleOffsetsPropertyName( unsigned int index ) const
646 DALI_ASSERT_ALWAYS( index < mNumSamples );
648 std::ostringstream oss;
649 oss << "uSampleOffsets[" << index << "]";
653 std::string GaussianBlurView::GetSampleWeightsPropertyName( unsigned int index ) const
655 DALI_ASSERT_ALWAYS( index < mNumSamples );
657 std::ostringstream oss;
658 oss << "uSampleWeights[" << index << "]";
662 Dali::Toolkit::GaussianBlurView::GaussianBlurViewSignal& GaussianBlurView::FinishedSignal()
664 return mFinishedSignal;
667 void GaussianBlurView::OnRenderTaskFinished(Dali::RenderTask& renderTask)
669 Toolkit::GaussianBlurView handle( GetOwner() );
670 mFinishedSignal.Emit( handle );
673 } // namespace Internal
674 } // namespace Toolkit