2 * Copyright (c) 2020 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/constraint.h>
25 #include <dali/public-api/animation/constraints.h>
26 #include <dali/devel-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/renderer.h>
31 #include <dali/public-api/rendering/shader.h>
32 #include <dali/public-api/render-tasks/render-task-list.h>
33 #include <dali/integration-api/debug.h>
34 #include <dali/devel-api/actors/actor-devel.h>
37 #include <dali-toolkit/public-api/visuals/visual-properties.h>
38 #include <dali-toolkit/internal/controls/control/control-renderers.h>
39 #include <dali-toolkit/internal/controls/control/control-data-impl.h>
40 #include <dali-toolkit/internal/graphics/builtin-shader-extern-gen.h>
43 // pixel format / size - set from JSON
44 // 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
45 // default near clip value
46 // Manager object - re-use render targets if there are multiple GaussianBlurViews created
49 /////////////////////////////////////////////////////////
50 // IMPLEMENTATION NOTES
52 // As the GaussianBlurView actor changes size, the amount of pixels we need to blur changes. Therefore we need some way of doing this. However:-
53 // OnSetSize() does not get called when GaussianBlurView object size is modified using a Constraint.
54 // 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
55 // OnSizeAnimation() to alter render target sizes.
56 // 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
57 // 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
58 // by using constraints relative to the GaussianBlurView actor size.
62 // 1st mode, this control has a tree of actors (use Add() to add children) that are rendered and blurred.
63 // mRenderChildrenTask renders children to FB mRenderTargetForRenderingChildren
64 // mHorizBlurTask renders mHorizBlurActor Actor showing FB mRenderTargetForRenderingChildren into FB mRenderTarget2
65 // mVertBlurTask renders mVertBlurActor Actor showing FB mRenderTarget2 into FB mRenderTarget1
66 // mCompositeTask renders mCompositingActor Actor showing FB mRenderTarget1 into FB mRenderTargetForRenderingChildren
68 // 2nd mode, an image is blurred and rendered to a supplied target framebuffer
69 // mHorizBlurTask renders mHorizBlurActor Actor showing mUserInputImage into FB mRenderTarget2
70 // mVertBlurTask renders mVertBlurActor Actor showing mRenderTarget2 into FB mUserOutputRenderTarget
72 // Only this 2nd mode handles ActivateOnce
90 return Toolkit::GaussianBlurView::New();
93 DALI_TYPE_REGISTRATION_BEGIN( Toolkit::GaussianBlurView, Toolkit::Control, Create )
94 DALI_TYPE_REGISTRATION_END()
96 const unsigned int GAUSSIAN_BLUR_VIEW_DEFAULT_NUM_SAMPLES = 5;
97 const float GAUSSIAN_BLUR_VIEW_DEFAULT_BLUR_BELL_CURVE_WIDTH = 1.5f;
98 const Pixel::Format GAUSSIAN_BLUR_VIEW_DEFAULT_RENDER_TARGET_PIXEL_FORMAT = Pixel::RGBA8888;
99 const float GAUSSIAN_BLUR_VIEW_DEFAULT_BLUR_STRENGTH = 1.0f; // default, fully blurred
100 const char* const GAUSSIAN_BLUR_VIEW_STRENGTH_PROPERTY_NAME = "GaussianBlurStrengthPropertyName";
101 const float GAUSSIAN_BLUR_VIEW_DEFAULT_DOWNSAMPLE_WIDTH_SCALE = 0.5f;
102 const float GAUSSIAN_BLUR_VIEW_DEFAULT_DOWNSAMPLE_HEIGHT_SCALE = 0.5f;
104 const float ARBITRARY_FIELD_OF_VIEW = Math::PI / 4.0f;
109 GaussianBlurView::GaussianBlurView()
110 : Control( ControlBehaviour( DISABLE_SIZE_NEGOTIATION | DISABLE_STYLE_CHANGE_SIGNALS ) ),
111 mNumSamples(GAUSSIAN_BLUR_VIEW_DEFAULT_NUM_SAMPLES),
112 mBlurBellCurveWidth( 0.001f ),
113 mPixelFormat(GAUSSIAN_BLUR_VIEW_DEFAULT_RENDER_TARGET_PIXEL_FORMAT),
114 mDownsampleWidthScale(GAUSSIAN_BLUR_VIEW_DEFAULT_DOWNSAMPLE_WIDTH_SCALE),
115 mDownsampleHeightScale(GAUSSIAN_BLUR_VIEW_DEFAULT_DOWNSAMPLE_HEIGHT_SCALE),
116 mDownsampledWidth( 0.0f ),
117 mDownsampledHeight( 0.0f ),
118 mBlurUserImage( false ),
119 mRenderOnce( false ),
120 mBackgroundColor( Color::BLACK ),
121 mTargetSize(Vector2::ZERO),
122 mLastSize(Vector2::ZERO),
123 mChildrenRoot(Actor::New()),
124 mInternalRoot(Actor::New()),
125 mBlurStrengthPropertyIndex(Property::INVALID_INDEX),
128 SetBlurBellCurveWidth(GAUSSIAN_BLUR_VIEW_DEFAULT_BLUR_BELL_CURVE_WIDTH);
131 GaussianBlurView::GaussianBlurView( const unsigned int numSamples,
132 const float blurBellCurveWidth,
133 const Pixel::Format renderTargetPixelFormat,
134 const float downsampleWidthScale,
135 const float downsampleHeightScale,
137 : Control( ControlBehaviour( DISABLE_SIZE_NEGOTIATION | DISABLE_STYLE_CHANGE_SIGNALS ) ),
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 mInternalRoot(Actor::New()),
152 mBlurStrengthPropertyIndex(Property::INVALID_INDEX),
155 SetBlurBellCurveWidth(blurBellCurveWidth);
158 GaussianBlurView::~GaussianBlurView()
163 Toolkit::GaussianBlurView GaussianBlurView::New()
165 GaussianBlurView* impl = new GaussianBlurView();
167 Dali::Toolkit::GaussianBlurView handle = Dali::Toolkit::GaussianBlurView( *impl );
169 // Second-phase init of the implementation
170 // This can only be done after the CustomActor connection has been made...
176 Toolkit::GaussianBlurView GaussianBlurView::New(const unsigned int numSamples, const float blurBellCurveWidth, const Pixel::Format renderTargetPixelFormat,
177 const float downsampleWidthScale, const float downsampleHeightScale,
180 GaussianBlurView* impl = new GaussianBlurView( numSamples, blurBellCurveWidth, renderTargetPixelFormat,
181 downsampleWidthScale, downsampleHeightScale,
184 Dali::Toolkit::GaussianBlurView handle = Dali::Toolkit::GaussianBlurView( *impl );
186 // Second-phase init of the implementation
187 // This can only be done after the CustomActor connection has been made...
193 void GaussianBlurView::SetUserImageAndOutputRenderTarget(Texture inputImage, FrameBuffer outputRenderTarget)
195 // can only do this if the GaussianBlurView object was created with this parameter set
196 DALI_ASSERT_ALWAYS(mBlurUserImage);
198 mUserInputImage = inputImage;
200 SetRendererTexture( mHorizBlurActor.GetRendererAt(0), inputImage );
202 mUserOutputRenderTarget = outputRenderTarget;
205 FrameBuffer GaussianBlurView::GetBlurredRenderTarget() const
207 if(!mUserOutputRenderTarget)
209 return mRenderTargetForRenderingChildren;
212 return mUserOutputRenderTarget;
215 void GaussianBlurView::SetBackgroundColor( const Vector4& color )
217 mBackgroundColor = color;
220 Vector4 GaussianBlurView::GetBackgroundColor() const
222 return mBackgroundColor;
225 ///////////////////////////////////////////////////////////
230 void GaussianBlurView::OnInitialize()
232 // root actor to parent all user added actors, needed to allow us to set that subtree as exclusive for our child render task
233 mChildrenRoot.SetProperty( Actor::Property::PARENT_ORIGIN,ParentOrigin::CENTER );
234 mInternalRoot.SetProperty( Actor::Property::PARENT_ORIGIN,ParentOrigin::CENTER );
236 //////////////////////////////////////////////////////
239 std::ostringstream fragmentStringStream;
240 fragmentStringStream << "#define NUM_SAMPLES " << mNumSamples << "\n";
241 fragmentStringStream << SHADER_GAUSSIAN_BLUR_VIEW_FRAG;
242 std::string fragmentSource(fragmentStringStream.str());
244 //////////////////////////////////////////////////////
247 // Create an actor for performing a horizontal blur on the texture
248 mHorizBlurActor = Actor::New();
249 mHorizBlurActor.SetProperty( Actor::Property::PARENT_ORIGIN,ParentOrigin::CENTER );
251 Renderer renderer = CreateRenderer( BASIC_VERTEX_SOURCE, fragmentSource.c_str() );
252 mHorizBlurActor.AddRenderer( renderer );
254 // Create an actor for performing a vertical blur on the texture
255 mVertBlurActor = Actor::New();
256 mVertBlurActor.SetProperty( Actor::Property::PARENT_ORIGIN,ParentOrigin::CENTER );
257 renderer = CreateRenderer( BASIC_VERTEX_SOURCE, fragmentSource.c_str() );
258 mVertBlurActor.AddRenderer( renderer );
260 // Register a property that the user can control to fade the blur in / out via the GaussianBlurView object
262 mBlurStrengthPropertyIndex = self.RegisterProperty(GAUSSIAN_BLUR_VIEW_STRENGTH_PROPERTY_NAME, GAUSSIAN_BLUR_VIEW_DEFAULT_BLUR_STRENGTH);
264 // Create an image view for compositing the blur and the original child actors render
267 mCompositingActor = Actor::New();
268 mCompositingActor.SetProperty( Actor::Property::PARENT_ORIGIN,ParentOrigin::CENTER );
269 mCompositingActor.SetProperty( Actor::Property::OPACITY,GAUSSIAN_BLUR_VIEW_DEFAULT_BLUR_STRENGTH); // ensure alpha is enabled for this object and set default value
270 renderer = CreateRenderer( BASIC_VERTEX_SOURCE, BASIC_FRAGMENT_SOURCE );
271 mCompositingActor.AddRenderer( renderer );
273 Constraint blurStrengthConstraint = Constraint::New<float>( mCompositingActor, Actor::Property::COLOR_ALPHA, EqualToConstraint());
274 blurStrengthConstraint.AddSource( Source( self, mBlurStrengthPropertyIndex) );
275 blurStrengthConstraint.Apply();
277 // 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
278 mTargetActor = Actor::New();
279 mTargetActor.SetProperty( Actor::Property::PARENT_ORIGIN,ParentOrigin::CENTER );
280 renderer = CreateRenderer( BASIC_VERTEX_SOURCE, BASIC_FRAGMENT_SOURCE );
281 mTargetActor.AddRenderer( renderer );
283 //////////////////////////////////////////////////////
284 // Create cameras for the renders corresponding to the view size
285 mRenderFullSizeCamera = CameraActor::New();
286 mRenderFullSizeCamera.SetInvertYAxis( true );
287 mRenderFullSizeCamera.SetProperty( Actor::Property::PARENT_ORIGIN,ParentOrigin::CENTER );
289 //////////////////////////////////////////////////////
290 // Connect to actor tree
291 mInternalRoot.Add( mCompositingActor );
292 mInternalRoot.Add( mTargetActor );
293 mInternalRoot.Add( mRenderFullSizeCamera );
296 //////////////////////////////////////////////////////
297 // Create camera for the renders corresponding to the (potentially downsampled) render targets' size
298 mRenderDownsampledCamera = CameraActor::New();
299 mRenderDownsampledCamera.SetInvertYAxis( true );
300 mRenderDownsampledCamera.SetProperty( Actor::Property::PARENT_ORIGIN,ParentOrigin::CENTER );
302 //////////////////////////////////////////////////////
303 // Connect to actor tree
304 Self().Add( mChildrenRoot );
305 mInternalRoot.Add( mHorizBlurActor );
306 mInternalRoot.Add( mVertBlurActor );
307 mInternalRoot.Add( mRenderDownsampledCamera );
309 DevelControl::SetAccessibilityConstructor( Self(), []( Dali::Actor actor ) {
310 return std::unique_ptr< Dali::Accessibility::Accessible >(
311 new Control::Impl::AccessibleImpl( actor, Dali::Accessibility::Role::FILLER ) );
316 void GaussianBlurView::OnSizeSet(const Vector3& targetSize)
318 mTargetSize = Vector2(targetSize);
320 mChildrenRoot.SetProperty( Actor::Property::SIZE, targetSize);
322 if( !mBlurUserImage )
324 mCompositingActor.SetProperty( Actor::Property::SIZE, targetSize);
325 mTargetActor.SetProperty( Actor::Property::SIZE, targetSize);
327 // 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
328 // 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
329 // size, this is the trade off for not being able to modify render target size
330 // Change camera z position based on GaussianBlurView actor height
331 float cameraPosConstraintScale = 0.5f / tanf(ARBITRARY_FIELD_OF_VIEW * 0.5f);
332 mRenderFullSizeCamera.SetProperty( Actor::Property::POSITION_Z, mTargetSize.height * cameraPosConstraintScale);
336 // if we have already activated the blur, need to update render target sizes now to reflect the new size of this actor
343 Control::OnSizeSet( targetSize );
346 void GaussianBlurView::OnChildAdd( Actor& child )
348 if( child != mChildrenRoot && child != mInternalRoot)
350 mChildrenRoot.Add( child );
353 Control::OnChildAdd( child );
356 void GaussianBlurView::OnChildRemove( Actor& child )
358 mChildrenRoot.Remove( child );
360 Control::OnChildRemove( child );
363 void GaussianBlurView::AllocateResources()
365 mLastSize = mTargetSize;
367 // get size of downsampled render targets
368 mDownsampledWidth = mTargetSize.width * mDownsampleWidthScale;
369 mDownsampledHeight = mTargetSize.height * mDownsampleHeightScale;
371 // Create and place a camera for the renders corresponding to the (potentially downsampled) render targets' size
372 mRenderDownsampledCamera.SetFieldOfView(ARBITRARY_FIELD_OF_VIEW);
373 // 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
374 mRenderDownsampledCamera.SetNearClippingPlane(1.0f);
375 mRenderDownsampledCamera.SetAspectRatio(mDownsampledWidth / mDownsampledHeight);
376 mRenderDownsampledCamera.SetType(Dali::Camera::FREE_LOOK); // camera orientation based solely on actor
378 mRenderDownsampledCamera.SetProperty( Actor::Property::POSITION, Vector3(0.0f, 0.0f, ((mDownsampledHeight * 0.5f) / tanf(ARBITRARY_FIELD_OF_VIEW * 0.5f))));
380 // setup for normal operation
383 // Create and place a camera for the children render, corresponding to its render target size
384 mRenderFullSizeCamera.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 mRenderFullSizeCamera.SetNearClippingPlane(1.0f);
387 mRenderFullSizeCamera.SetAspectRatio(mTargetSize.width / mTargetSize.height);
388 mRenderFullSizeCamera.SetType(Dali::Camera::FREE_LOOK); // camera orientation based solely on actor
390 float cameraPosConstraintScale = 0.5f / tanf(ARBITRARY_FIELD_OF_VIEW * 0.5f);
391 mRenderFullSizeCamera.SetProperty( Actor::Property::POSITION, Vector3(0.0f, 0.0f, mTargetSize.height * cameraPosConstraintScale));
393 // create offscreen buffer of new size to render our child actors to
394 mRenderTargetForRenderingChildren = FrameBuffer::New( mTargetSize.width, mTargetSize.height, FrameBuffer::Attachment::NONE );
395 Texture texture = Texture::New( TextureType::TEXTURE_2D, mPixelFormat, unsigned(mTargetSize.width), unsigned(mTargetSize.height) );
396 mRenderTargetForRenderingChildren.AttachColorTexture( texture );
398 // Set actor for performing a horizontal blur
399 SetRendererTexture( mHorizBlurActor.GetRendererAt(0), mRenderTargetForRenderingChildren );
401 // Create offscreen buffer for vert blur pass
402 mRenderTarget1 = FrameBuffer::New( mDownsampledWidth, mDownsampledHeight, FrameBuffer::Attachment::NONE );
403 texture = Texture::New(TextureType::TEXTURE_2D, mPixelFormat, unsigned(mDownsampledWidth), unsigned(mDownsampledHeight));
404 mRenderTarget1.AttachColorTexture( texture );
406 // use the completed blur in the first buffer and composite with the original child actors render
407 SetRendererTexture( mCompositingActor.GetRendererAt(0), mRenderTarget1 );
409 // set up target actor for rendering result, i.e. the blurred image
410 SetRendererTexture( mTargetActor.GetRendererAt(0), mRenderTargetForRenderingChildren );
413 // Create offscreen buffer for horiz blur pass
414 mRenderTarget2 = FrameBuffer::New( mDownsampledWidth, mDownsampledHeight, FrameBuffer::Attachment::NONE );
415 Texture texture = Texture::New(TextureType::TEXTURE_2D, mPixelFormat, unsigned(mDownsampledWidth), unsigned(mDownsampledHeight));
416 mRenderTarget2.AttachColorTexture( texture );
418 // size needs to match render target
419 mHorizBlurActor.SetProperty( Actor::Property::SIZE, Vector2(mDownsampledWidth, mDownsampledHeight) );
421 // size needs to match render target
422 mVertBlurActor.SetProperty( Actor::Property::SIZE, Vector2(mDownsampledWidth, mDownsampledHeight) );
423 SetRendererTexture( mVertBlurActor.GetRendererAt(0), mRenderTarget2 );
425 // set gaussian blur up for new sized render targets
426 SetShaderConstants();
429 void GaussianBlurView::CreateRenderTasks()
431 RenderTaskList taskList = Stage::GetCurrent().GetRenderTaskList();
435 // create render task to render our child actors to offscreen buffer
436 mRenderChildrenTask = taskList.CreateTask();
437 mRenderChildrenTask.SetSourceActor( mChildrenRoot );
438 mRenderChildrenTask.SetExclusive(true);
439 mRenderChildrenTask.SetInputEnabled( false );
440 mRenderChildrenTask.SetClearEnabled( true );
441 mRenderChildrenTask.SetClearColor( mBackgroundColor );
443 mRenderChildrenTask.SetCameraActor(mRenderFullSizeCamera);
444 mRenderChildrenTask.SetFrameBuffer( mRenderTargetForRenderingChildren );
448 mRenderChildrenTask.SetRefreshRate(RenderTask::REFRESH_ONCE);
452 // perform a horizontal blur targeting the second buffer
453 mHorizBlurTask = taskList.CreateTask();
454 mHorizBlurTask.SetSourceActor( mHorizBlurActor );
455 mHorizBlurTask.SetExclusive(true);
456 mHorizBlurTask.SetInputEnabled( false );
457 mHorizBlurTask.SetClearEnabled( true );
458 mHorizBlurTask.SetClearColor( mBackgroundColor );
459 mHorizBlurTask.SetCameraActor(mRenderDownsampledCamera);
460 mHorizBlurTask.SetFrameBuffer( mRenderTarget2 );
461 if( mRenderOnce || ( mRenderOnce && mBlurUserImage ) )
463 mHorizBlurTask.SetRefreshRate(RenderTask::REFRESH_ONCE);
466 // use the second buffer and perform a horizontal blur targeting the first buffer
467 mVertBlurTask = taskList.CreateTask();
468 mVertBlurTask.SetSourceActor( mVertBlurActor );
469 mVertBlurTask.SetExclusive(true);
470 mVertBlurTask.SetInputEnabled( false );
471 mVertBlurTask.SetClearEnabled( true );
472 mVertBlurTask.SetClearColor( mBackgroundColor );
473 mVertBlurTask.SetCameraActor(mRenderDownsampledCamera);
474 if(mUserOutputRenderTarget)
476 mVertBlurTask.SetFrameBuffer( mUserOutputRenderTarget );
480 mVertBlurTask.SetFrameBuffer( mRenderTarget1 );
482 if( mRenderOnce || ( mRenderOnce && mBlurUserImage ) )
484 mVertBlurTask.SetRefreshRate(RenderTask::REFRESH_ONCE);
485 mVertBlurTask.FinishedSignal().Connect( this, &GaussianBlurView::OnRenderTaskFinished );
488 // use the completed blur in the first buffer and composite with the original child actors render
491 mCompositeTask = taskList.CreateTask();
492 mCompositeTask.SetSourceActor( mCompositingActor );
493 mCompositeTask.SetExclusive(true);
494 mCompositeTask.SetInputEnabled( false );
496 mCompositeTask.SetCameraActor(mRenderFullSizeCamera);
497 mCompositeTask.SetFrameBuffer( mRenderTargetForRenderingChildren );
501 mCompositeTask.SetRefreshRate(RenderTask::REFRESH_ONCE);
506 void GaussianBlurView::RemoveRenderTasks()
508 RenderTaskList taskList = Stage::GetCurrent().GetRenderTaskList();
510 taskList.RemoveTask(mRenderChildrenTask);
511 taskList.RemoveTask(mHorizBlurTask);
512 taskList.RemoveTask(mVertBlurTask);
513 taskList.RemoveTask(mCompositeTask);
516 void GaussianBlurView::Activate()
520 // make sure resources are allocated and start the render tasks processing
521 Self().Add( mInternalRoot );
528 void GaussianBlurView::ActivateOnce()
535 void GaussianBlurView::Deactivate()
539 // stop render tasks processing
540 // Note: render target resources are automatically freed since we set the Image::Unused flag
541 mInternalRoot.Unparent();
542 mRenderTargetForRenderingChildren.Reset();
543 mRenderTarget1.Reset();
544 mRenderTarget2.Reset();
551 void GaussianBlurView::SetBlurBellCurveWidth(float blurBellCurveWidth)
553 // a value of zero leads to undefined Gaussian weights, do not allow user to do this
554 mBlurBellCurveWidth = std::max( blurBellCurveWidth, 0.001f );
557 float GaussianBlurView::CalcGaussianWeight(float x)
559 return (1.0f / sqrt(2.0f * Math::PI * mBlurBellCurveWidth)) * exp(-(x * x) / (2.0f * mBlurBellCurveWidth * mBlurBellCurveWidth));
562 void GaussianBlurView::SetShaderConstants()
567 float w, totalWeights;
570 uvOffsets = new Vector2[mNumSamples + 1];
571 weights = new float[mNumSamples + 1];
573 totalWeights = weights[0] = CalcGaussianWeight(0);
574 uvOffsets[0].x = 0.0f;
575 uvOffsets[0].y = 0.0f;
577 for(i=0; i<mNumSamples >> 1; i++)
579 w = CalcGaussianWeight((float)(i + 1));
580 weights[(i << 1) + 1] = w;
581 weights[(i << 1) + 2] = w;
582 totalWeights += w * 2.0f;
584 // offset texture lookup to between texels, that way the bilinear filter in the texture hardware will average two samples with one lookup
585 ofs = ((float)(i << 1)) + 1.5f;
587 // get offsets from units of pixels into uv coordinates in [0..1]
588 float ofsX = ofs / mDownsampledWidth;
589 float ofsY = ofs / mDownsampledHeight;
590 uvOffsets[(i << 1) + 1].x = ofsX;
591 uvOffsets[(i << 1) + 1].y = ofsY;
593 uvOffsets[(i << 1) + 2].x = -ofsX;
594 uvOffsets[(i << 1) + 2].y = -ofsY;
597 for(i=0; i<mNumSamples; i++)
599 weights[i] /= totalWeights;
602 // set shader constants
603 Vector2 xAxis(1.0f, 0.0f);
604 Vector2 yAxis(0.0f, 1.0f);
605 for (i = 0; i < mNumSamples; ++i )
607 mHorizBlurActor.RegisterProperty( GetSampleOffsetsPropertyName( i ), uvOffsets[ i ] * xAxis );
608 mHorizBlurActor.RegisterProperty( GetSampleWeightsPropertyName( i ), weights[ i ] );
610 mVertBlurActor.RegisterProperty( GetSampleOffsetsPropertyName( i ), uvOffsets[ i ] * yAxis );
611 mVertBlurActor.RegisterProperty( GetSampleWeightsPropertyName( i ), weights[ i ] );
618 std::string GaussianBlurView::GetSampleOffsetsPropertyName( unsigned int index ) const
620 DALI_ASSERT_ALWAYS( index < mNumSamples );
622 std::ostringstream oss;
623 oss << "uSampleOffsets[" << index << "]";
627 std::string GaussianBlurView::GetSampleWeightsPropertyName( unsigned int index ) const
629 DALI_ASSERT_ALWAYS( index < mNumSamples );
631 std::ostringstream oss;
632 oss << "uSampleWeights[" << index << "]";
636 Dali::Toolkit::GaussianBlurView::GaussianBlurViewSignal& GaussianBlurView::FinishedSignal()
638 return mFinishedSignal;
641 void GaussianBlurView::OnRenderTaskFinished(Dali::RenderTask& renderTask)
643 Toolkit::GaussianBlurView handle( GetOwner() );
644 mFinishedSignal.Emit( handle );
647 } // namespace Internal
648 } // namespace Toolkit