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"
26 #include <dali-toolkit/public-api/controls/gaussian-blur-view/gaussian-blur-view.h>
28 #include <dali/integration-api/debug.h>
31 // pixel format / size - set from JSON
32 // 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
33 // default near clip value
34 // mChildrenRoot Add()/Remove() overloads - better solution
35 // Manager object - re-use render targets if there are multiple GaussianBlurViews created
39 /////////////////////////////////////////////////////////
40 // IMPLEMENTATION NOTES
42 // As the GaussianBlurView actor changes size, the amount of pixels we need to blur changes. Therefore we need some way of doing this. However:-
43 // OnSetSize() does not get called when GaussianBlurView object size is modified using a Constraint.
44 // 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
45 // OnSizeAnimation() to alter render target sizes.
46 // 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
47 // 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
48 // by using constraints relative to the GaussianBlurView actor size.
52 // 1st mode, this control has a tree of actors (use Add() to add children) that are rendered and blurred.
53 // mRenderChildrenTask renders children to FB mRenderTargetForRenderingChildren
54 // mHorizBlurTask renders mImageActorHorizBlur Actor showing FB mRenderTargetForRenderingChildren into FB mRenderTarget2
55 // mVertBlurTask renders mImageActorVertBlur Actor showing FB mRenderTarget2 into FB mRenderTarget1
56 // mCompositeTask renders mImageActorComposite Actor showing FB mRenderTarget1 into FB mRenderTargetForRenderingChildren
58 // 2nd mode, an image is blurred and rendered to a supplied target framebuffer
59 // mHorizBlurTask renders mImageActorHorizBlur Actor showing mUserInputImage into FB mRenderTarget2
60 // mVertBlurTask renders mImageActorVertBlur Actor showing mRenderTarget2 into FB mUserOutputRenderTarget
62 // Only this 2nd mode handles ActivateOnce
80 return Toolkit::GaussianBlurView::New();
83 TypeRegistration mType( typeid(Toolkit::GaussianBlurView), typeid(Toolkit::Control), Create );
86 const unsigned int GAUSSIAN_BLUR_VIEW_DEFAULT_NUM_SAMPLES = 5;
87 const float GAUSSIAN_BLUR_VIEW_DEFAULT_BLUR_BELL_CURVE_WIDTH = 1.5f;
88 const Pixel::Format GAUSSIAN_BLUR_VIEW_DEFAULT_RENDER_TARGET_PIXEL_FORMAT = Pixel::RGBA8888;
89 const float GAUSSIAN_BLUR_VIEW_DEFAULT_BLUR_STRENGTH = 1.0f; // default, fully blurred
90 const std::string GAUSSIAN_BLUR_VIEW_STRENGTH_PROPERTY_NAME("GaussianBlurStrengthPropertyName");
91 const float GAUSSIAN_BLUR_VIEW_DEFAULT_DOWNSAMPLE_WIDTH_SCALE = 0.5f;
92 const float GAUSSIAN_BLUR_VIEW_DEFAULT_DOWNSAMPLE_HEIGHT_SCALE = 0.5f;
94 const float ARBITRARY_FIELD_OF_VIEW = Math::PI / 4.0f;
96 const char* const GAUSSIAN_BLUR_FRAGMENT_SOURCE =
97 "uniform vec2 uSampleOffsets[NUM_SAMPLES];\n"
98 "uniform float uSampleWeights[NUM_SAMPLES];\n"
102 " mediump vec4 col;\n"
103 " col = texture2D(sTexture, vec2(vTexCoord.x, vTexCoord.y) + uSampleOffsets[0]) * uSampleWeights[0]; \n"
104 " for (int i=1; i<NUM_SAMPLES; ++i) \n"
106 " col += texture2D(sTexture, vec2(vTexCoord.x, vTexCoord.y) + uSampleOffsets[i]) * uSampleWeights[i]; \n"
108 " gl_FragColor = col;\n"
114 GaussianBlurView::GaussianBlurView()
115 : Control( CONTROL_BEHAVIOUR_NONE )
116 , mNumSamples(GAUSSIAN_BLUR_VIEW_DEFAULT_NUM_SAMPLES)
117 , mBlurBellCurveWidth( 0.001f )
118 , mPixelFormat(GAUSSIAN_BLUR_VIEW_DEFAULT_RENDER_TARGET_PIXEL_FORMAT)
119 , mDownsampleWidthScale(GAUSSIAN_BLUR_VIEW_DEFAULT_DOWNSAMPLE_WIDTH_SCALE)
120 , mDownsampleHeightScale(GAUSSIAN_BLUR_VIEW_DEFAULT_DOWNSAMPLE_HEIGHT_SCALE)
121 , mDownsampledWidth( 0.0f )
122 , mDownsampledHeight( 0.0f )
123 , mBlurUserImage( false )
124 , mRenderOnce( false )
125 , mBackgroundColor( Color::BLACK )
126 , mTargetSize(Vector2::ZERO)
127 , mLastSize(Vector2::ZERO)
128 , mChildrenRoot(Actor::New())
129 , mBlurStrengthPropertyIndex(Property::INVALID_INDEX)
131 SetBlurBellCurveWidth(GAUSSIAN_BLUR_VIEW_DEFAULT_BLUR_BELL_CURVE_WIDTH);
134 GaussianBlurView::GaussianBlurView( const unsigned int numSamples, const float blurBellCurveWidth, const Pixel::Format renderTargetPixelFormat,
135 const float downsampleWidthScale, const float downsampleHeightScale,
137 : Control( CONTROL_BEHAVIOUR_NONE )
138 , mNumSamples(numSamples)
139 , mBlurBellCurveWidth( 0.001f )
140 , mPixelFormat(renderTargetPixelFormat)
141 , mDownsampleWidthScale(downsampleWidthScale)
142 , mDownsampleHeightScale(downsampleHeightScale)
143 , mDownsampledWidth( 0.0f )
144 , mDownsampledHeight( 0.0f )
145 , mBlurUserImage( blurUserImage )
146 , mRenderOnce( false )
147 , mBackgroundColor( Color::BLACK )
148 , mTargetSize(Vector2::ZERO)
149 , mLastSize(Vector2::ZERO)
150 , mChildrenRoot(Actor::New())
151 , mBlurStrengthPropertyIndex(Property::INVALID_INDEX)
153 SetBlurBellCurveWidth(blurBellCurveWidth);
156 GaussianBlurView::~GaussianBlurView()
161 Toolkit::GaussianBlurView GaussianBlurView::New()
163 GaussianBlurView* impl = new GaussianBlurView();
165 Dali::Toolkit::GaussianBlurView handle = Dali::Toolkit::GaussianBlurView( *impl );
167 // Second-phase init of the implementation
168 // This can only be done after the CustomActor connection has been made...
174 Toolkit::GaussianBlurView GaussianBlurView::New(const unsigned int numSamples, const float blurBellCurveWidth, const Pixel::Format renderTargetPixelFormat,
175 const float downsampleWidthScale, const float downsampleHeightScale,
178 GaussianBlurView* impl = new GaussianBlurView( numSamples, blurBellCurveWidth, renderTargetPixelFormat,
179 downsampleWidthScale, downsampleHeightScale,
182 Dali::Toolkit::GaussianBlurView handle = Dali::Toolkit::GaussianBlurView( *impl );
184 // Second-phase init of the implementation
185 // This can only be done after the CustomActor connection has been made...
191 /////////////////////////////////////////////////////////////
192 // 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
193 // 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.
194 void GaussianBlurView::Add(Actor child)
196 mChildrenRoot.Add(child);
199 void GaussianBlurView::Remove(Actor child)
201 mChildrenRoot.Remove(child);
204 void GaussianBlurView::SetUserImageAndOutputRenderTarget(Image inputImage, FrameBufferImage outputRenderTarget)
206 // can only do this if the GaussianBlurView object was created with this parameter set
207 DALI_ASSERT_ALWAYS(mBlurUserImage);
209 mUserInputImage = inputImage;
210 mImageActorHorizBlur.SetImage( mUserInputImage );
212 mUserOutputRenderTarget = outputRenderTarget;
215 FrameBufferImage GaussianBlurView::GetBlurredRenderTarget() const
217 if(!mUserOutputRenderTarget)
219 return mRenderTargetForRenderingChildren;
222 return mUserOutputRenderTarget;
225 void GaussianBlurView::SetBackgroundColor( const Vector4& color )
227 mBackgroundColor = color;
230 Vector4 GaussianBlurView::GetBackgroundColor() const
232 return mBackgroundColor;
235 ///////////////////////////////////////////////////////////
241 * EqualToConstraintFloat
243 * f(current, property) = property
245 struct EqualToConstraintFloat
247 EqualToConstraintFloat(){}
249 float operator()(const float current, const PropertyInput& property) {return property.GetFloat();}
252 void GaussianBlurView::OnInitialize()
254 // root actor to parent all user added actors, needed to allow us to set that subtree as exclusive for our child render task
255 mChildrenRoot.SetParentOrigin(ParentOrigin::CENTER);
256 mChildrenRoot.ApplyConstraint( Constraint::New<Vector3>( Actor::SIZE, ParentSource( Actor::SIZE ), EqualToConstraint() ) ); // same size as GaussianBlurView object
259 //////////////////////////////////////////////////////
263 std::ostringstream horizFragmentShaderStringStream;
264 horizFragmentShaderStringStream << "#define NUM_SAMPLES " << mNumSamples << "\n";
265 horizFragmentShaderStringStream << GAUSSIAN_BLUR_FRAGMENT_SOURCE;
266 mHorizBlurShader = ShaderEffect::New( "", horizFragmentShaderStringStream.str() );
268 std::ostringstream vertFragmentShaderStringStream;
269 vertFragmentShaderStringStream << "#define NUM_SAMPLES " << mNumSamples << "\n";
270 vertFragmentShaderStringStream << GAUSSIAN_BLUR_FRAGMENT_SOURCE;
271 mVertBlurShader = ShaderEffect::New( "", vertFragmentShaderStringStream.str() );
274 //////////////////////////////////////////////////////
277 // Create an ImageActor for performing a horizontal blur on the texture
278 mImageActorHorizBlur = ImageActor::New();
279 mImageActorHorizBlur.SetParentOrigin(ParentOrigin::CENTER);
280 mImageActorHorizBlur.ScaleBy( Vector3(1.0f, -1.0f, 1.0f) ); // FIXME
281 mImageActorHorizBlur.SetShaderEffect( mHorizBlurShader );
283 // Create an ImageActor for performing a vertical blur on the texture
284 mImageActorVertBlur = ImageActor::New();
285 mImageActorVertBlur.SetParentOrigin(ParentOrigin::CENTER);
286 mImageActorVertBlur.ScaleBy( Vector3(1.0f, -1.0f, 1.0f) ); // FIXME
287 mImageActorVertBlur.SetShaderEffect( mVertBlurShader );
289 // Register a property that the user can control to fade the blur in / out via the GaussianBlurView object
290 mBlurStrengthPropertyIndex = Self().RegisterProperty(GAUSSIAN_BLUR_VIEW_STRENGTH_PROPERTY_NAME, GAUSSIAN_BLUR_VIEW_DEFAULT_BLUR_STRENGTH);
292 // Create an ImageActor for compositing the blur and the original child actors render
295 mImageActorComposite = ImageActor::New();
296 mImageActorComposite.SetParentOrigin(ParentOrigin::CENTER);
297 mImageActorComposite.ApplyConstraint( Constraint::New<Vector3>( Actor::SIZE, ParentSource( Actor::SIZE ), EqualToConstraint() ) ); // same size as GaussianBlurView object
298 mImageActorComposite.ScaleBy( Vector3(1.0f, -1.0f, 1.0f) ); // FIXME
299 mImageActorComposite.SetOpacity(GAUSSIAN_BLUR_VIEW_DEFAULT_BLUR_STRENGTH); // ensure alpha is enabled for this object and set default value
301 Constraint blurStrengthConstraint = Constraint::New<float>( Actor::COLOR_ALPHA, ParentSource(mBlurStrengthPropertyIndex), EqualToConstraintFloat());
302 mImageActorComposite.ApplyConstraint(blurStrengthConstraint);
304 // Create an ImageActor for holding final result, i.e. the blurred image. This will get rendered to screen later, via default / user render task
305 mTargetActor = ImageActor::New();
306 mTargetActor.SetParentOrigin(ParentOrigin::CENTER);
307 mTargetActor.ApplyConstraint( Constraint::New<Vector3>( Actor::SIZE, ParentSource( Actor::SIZE ), EqualToConstraint() ) ); // same size as GaussianBlurView object
308 mTargetActor.ScaleBy( Vector3(1.0f, -1.0f, 1.0f) ); // FIXME
311 //////////////////////////////////////////////////////
312 // Create cameras for the renders corresponding to the view size
313 mRenderFullSizeCamera = CameraActor::New();
314 mRenderFullSizeCamera.SetParentOrigin(ParentOrigin::CENTER);
317 //////////////////////////////////////////////////////
318 // Connect to actor tree
319 Self().Add( mImageActorComposite );
320 Self().Add( mTargetActor );
321 Self().Add( mRenderFullSizeCamera );
325 //////////////////////////////////////////////////////
326 // Create camera for the renders corresponding to the (potentially downsampled) render targets' size
327 mRenderDownsampledCamera = CameraActor::New();
328 mRenderDownsampledCamera.SetParentOrigin(ParentOrigin::CENTER);
331 //////////////////////////////////////////////////////
332 // Connect to actor tree
333 Self().Add( mChildrenRoot );
334 Self().Add( mImageActorHorizBlur );
335 Self().Add( mImageActorVertBlur );
336 Self().Add( mRenderDownsampledCamera );
341 * ZrelativeToYconstraint
343 * f(current, property, scale) = Vector3(current.x, current.y, property.y * scale)
345 struct ZrelativeToYconstraint
347 ZrelativeToYconstraint( float scale )
351 Vector3 operator()(const Vector3& current,
352 const PropertyInput& property)
358 v.z = property.GetVector3().y * mScale;
366 void GaussianBlurView::OnControlSizeSet(const Vector3& targetSize)
368 mTargetSize = Vector2(targetSize);
370 // if we are already on stage, need to update render target sizes now to reflect the new size of this actor
377 void GaussianBlurView::AllocateResources()
379 // size of render targets etc is based on the size of this actor, ignoring z
380 if(mTargetSize != mLastSize)
382 mLastSize = mTargetSize;
384 // get size of downsampled render targets
385 mDownsampledWidth = mTargetSize.width * mDownsampleWidthScale;
386 mDownsampledHeight = mTargetSize.height * mDownsampleHeightScale;
388 // Create and place a camera for the renders corresponding to the (potentially downsampled) render targets' size
389 mRenderDownsampledCamera.SetFieldOfView(ARBITRARY_FIELD_OF_VIEW);
390 // 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
391 mRenderDownsampledCamera.SetNearClippingPlane(1.0f);
392 mRenderDownsampledCamera.SetAspectRatio(mDownsampledWidth / mDownsampledHeight);
393 mRenderDownsampledCamera.SetType(Dali::Camera::FREE_LOOK); // camera orientation based solely on actor
394 // Point the camera back into the scene
395 mRenderDownsampledCamera.SetRotation(Quaternion(M_PI, Vector3::YAXIS));
397 mRenderDownsampledCamera.SetPosition(0.0f, 0.0f, ((mDownsampledHeight * 0.5f) / tanf(ARBITRARY_FIELD_OF_VIEW * 0.5f)));
399 // setup for normal operation
402 // Create and place a camera for the children render, corresponding to its render target size
403 mRenderFullSizeCamera.SetFieldOfView(ARBITRARY_FIELD_OF_VIEW);
404 // 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
405 mRenderFullSizeCamera.SetNearClippingPlane(1.0f);
406 mRenderFullSizeCamera.SetAspectRatio(mTargetSize.width / mTargetSize.height);
407 mRenderFullSizeCamera.SetType(Dali::Camera::FREE_LOOK); // camera orientation based solely on actor
408 // Point the camera back into the scene
409 mRenderFullSizeCamera.SetRotation(Quaternion(M_PI, Vector3::YAXIS));
411 float cameraPosConstraintScale = 0.5f / tanf(ARBITRARY_FIELD_OF_VIEW * 0.5f);
412 mRenderFullSizeCamera.SetPosition(0.0f, 0.0f, mTargetSize.height * cameraPosConstraintScale);
414 // 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
415 // 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
416 // size, this is the trade off for not being able to modify render target size
417 // Change camera z position based on GaussianBlurView actor height
418 mRenderFullSizeCamera.RemoveConstraints();
419 mRenderFullSizeCamera.ApplyConstraint( Constraint::New<Vector3>( Actor::POSITION, ParentSource( Actor::SIZE ), ZrelativeToYconstraint(cameraPosConstraintScale) ) );
421 // create offscreen buffer of new size to render our child actors to
422 mRenderTargetForRenderingChildren = FrameBufferImage::New( mTargetSize.width, mTargetSize.height, mPixelFormat, Dali::Image::Unused );
424 // Set ImageActor for performing a horizontal blur on the texture
425 mImageActorHorizBlur.SetImage( mRenderTargetForRenderingChildren );
427 // Create offscreen buffer for vert blur pass
428 mRenderTarget1 = FrameBufferImage::New( mDownsampledWidth, mDownsampledHeight, mPixelFormat, Dali::Image::Unused );
430 // use the completed blur in the first buffer and composite with the original child actors render
431 mImageActorComposite.SetImage( mRenderTarget1 );
433 // set up target actor for rendering result, i.e. the blurred image
434 mTargetActor.SetImage(mRenderTargetForRenderingChildren);
437 // Create offscreen buffer for horiz blur pass
438 mRenderTarget2 = FrameBufferImage::New( mDownsampledWidth, mDownsampledHeight, mPixelFormat, Dali::Image::Unused );
440 // size needs to match render target
441 mImageActorHorizBlur.SetSize(mDownsampledWidth, mDownsampledHeight);
443 // size needs to match render target
444 mImageActorVertBlur.SetImage( mRenderTarget2 );
445 mImageActorVertBlur.SetSize(mDownsampledWidth, mDownsampledHeight);
447 // set gaussian blur up for new sized render targets
448 SetShaderConstants();
452 void GaussianBlurView::CreateRenderTasks()
454 RenderTaskList taskList = Stage::GetCurrent().GetRenderTaskList();
458 // create render task to render our child actors to offscreen buffer
459 mRenderChildrenTask = taskList.CreateTask();
460 mRenderChildrenTask.SetSourceActor( mChildrenRoot );
461 mRenderChildrenTask.SetExclusive(true);
462 mRenderChildrenTask.SetInputEnabled( false );
463 mRenderChildrenTask.SetClearEnabled( true );
464 mRenderChildrenTask.SetClearColor( mBackgroundColor );
466 mRenderChildrenTask.SetCameraActor(mRenderFullSizeCamera);
467 mRenderChildrenTask.SetTargetFrameBuffer( mRenderTargetForRenderingChildren );
470 // perform a horizontal blur targeting the second buffer
471 mHorizBlurTask = taskList.CreateTask();
472 mHorizBlurTask.SetSourceActor( mImageActorHorizBlur );
473 mHorizBlurTask.SetExclusive(true);
474 mHorizBlurTask.SetInputEnabled( false );
475 mHorizBlurTask.SetClearEnabled( true );
476 mHorizBlurTask.SetClearColor( mBackgroundColor );
477 if( mRenderOnce && mBlurUserImage )
479 mHorizBlurTask.SetRefreshRate(RenderTask::REFRESH_ONCE);
482 // use the second buffer and perform a horizontal blur targeting the first buffer
483 mVertBlurTask = taskList.CreateTask();
484 mVertBlurTask.SetSourceActor( mImageActorVertBlur );
485 mVertBlurTask.SetExclusive(true);
486 mVertBlurTask.SetInputEnabled( false );
487 mVertBlurTask.SetClearEnabled( true );
488 mVertBlurTask.SetClearColor( mBackgroundColor );
489 if( mRenderOnce && mBlurUserImage )
491 mVertBlurTask.SetRefreshRate(RenderTask::REFRESH_ONCE);
492 mVertBlurTask.FinishedSignal().Connect( this, &GaussianBlurView::OnRenderTaskFinished );
495 // use the completed blur in the first buffer and composite with the original child actors render
498 mCompositeTask = taskList.CreateTask();
499 mCompositeTask.SetSourceActor( mImageActorComposite );
500 mCompositeTask.SetExclusive(true);
501 mCompositeTask.SetInputEnabled( false );
503 mCompositeTask.SetCameraActor(mRenderFullSizeCamera);
504 mCompositeTask.SetTargetFrameBuffer( mRenderTargetForRenderingChildren );
507 mHorizBlurTask.SetCameraActor(mRenderDownsampledCamera);
508 mVertBlurTask.SetCameraActor(mRenderDownsampledCamera);
510 mHorizBlurTask.SetTargetFrameBuffer( mRenderTarget2 );
511 if(mUserOutputRenderTarget)
513 mVertBlurTask.SetTargetFrameBuffer( mUserOutputRenderTarget );
517 mVertBlurTask.SetTargetFrameBuffer( mRenderTarget1 );
521 void GaussianBlurView::RemoveRenderTasks()
523 RenderTaskList taskList = Stage::GetCurrent().GetRenderTaskList();
525 taskList.RemoveTask(mRenderChildrenTask);
526 taskList.RemoveTask(mHorizBlurTask);
527 taskList.RemoveTask(mVertBlurTask);
528 taskList.RemoveTask(mCompositeTask);
531 void GaussianBlurView::OnStageDisconnection()
533 // TODO: can't call this here, since SetImage() calls fails similarly to above
534 // 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()
538 void GaussianBlurView::OnControlStageConnection()
540 // TODO: can't call this here, since SetImage() calls fail to connect images to stage, since parent chain not fully on stage yet
541 // 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()
545 void GaussianBlurView::Activate()
547 // make sure resources are allocated and start the render tasks processing
552 void GaussianBlurView::ActivateOnce()
554 DALI_ASSERT_ALWAYS(mBlurUserImage); // Only works with blurring image mode.
559 void GaussianBlurView::Deactivate()
561 // stop render tasks processing
562 // Note: render target resources are automatically freed since we set the Image::Unused flag
567 void GaussianBlurView::SetBlurBellCurveWidth(float blurBellCurveWidth)
569 // a value of zero leads to undefined Gaussian weights, do not allow user to do this
570 mBlurBellCurveWidth = std::max( blurBellCurveWidth, 0.001f );
573 float GaussianBlurView::CalcGaussianWeight(float x)
575 return (1.0f / sqrt(2.0f * Math::PI * mBlurBellCurveWidth)) * exp(-(x * x) / (2.0f * mBlurBellCurveWidth * mBlurBellCurveWidth));
578 void GaussianBlurView::SetShaderConstants()
583 float w, totalWeights;
586 uvOffsets = new Vector2[mNumSamples + 1];
587 weights = new float[mNumSamples + 1];
589 totalWeights = weights[0] = CalcGaussianWeight(0);
590 uvOffsets[0].x = 0.0f;
591 uvOffsets[0].y = 0.0f;
593 for(i=0; i<mNumSamples >> 1; i++)
595 w = CalcGaussianWeight((float)(i + 1));
596 weights[(i << 1) + 1] = w;
597 weights[(i << 1) + 2] = w;
598 totalWeights += w * 2.0f;
600 // offset texture lookup to between texels, that way the bilinear filter in the texture hardware will average two samples with one lookup
601 ofs = ((float)(i << 1)) + 1.5f;
603 // get offsets from units of pixels into uv coordinates in [0..1]
604 float ofsX = ofs / mDownsampledWidth;
605 float ofsY = ofs / mDownsampledHeight;
606 uvOffsets[(i << 1) + 1].x = ofsX;
607 uvOffsets[(i << 1) + 1].y = ofsY;
609 uvOffsets[(i << 1) + 2].x = -ofsX;
610 uvOffsets[(i << 1) + 2].y = -ofsY;
613 for(i=0; i<mNumSamples; i++)
615 weights[i] /= totalWeights;
618 // set shader constants
619 Vector2 xAxis(1.0f, 0.0f);
620 Vector2 yAxis(0.0f, 1.0f);
621 for (i = 0; i < mNumSamples; ++i )
623 mHorizBlurShader.SetUniform( GetSampleOffsetsPropertyName( i ), uvOffsets[ i ] * xAxis );
624 mHorizBlurShader.SetUniform( GetSampleWeightsPropertyName( i ), weights[ i ] );
626 mVertBlurShader.SetUniform( GetSampleOffsetsPropertyName( i ), uvOffsets[ i ] * yAxis );
627 mVertBlurShader.SetUniform( GetSampleWeightsPropertyName( i ), weights[ i ] );
634 std::string GaussianBlurView::GetSampleOffsetsPropertyName( unsigned int index ) const
636 DALI_ASSERT_ALWAYS( index < mNumSamples );
638 std::ostringstream oss;
639 oss << "uSampleOffsets[" << index << "]";
643 std::string GaussianBlurView::GetSampleWeightsPropertyName( unsigned int index ) const
645 DALI_ASSERT_ALWAYS( index < mNumSamples );
647 std::ostringstream oss;
648 oss << "uSampleWeights[" << index << "]";
652 Dali::Toolkit::GaussianBlurView::GaussianBlurViewSignal& GaussianBlurView::FinishedSignal()
654 return mFinishedSignal;
657 void GaussianBlurView::OnRenderTaskFinished(Dali::RenderTask& renderTask)
659 Toolkit::GaussianBlurView handle( GetOwner() );
660 mFinishedSignal.Emit( handle );
663 } // namespace Internal
664 } // namespace Toolkit