2 * Copyright (c) 2021 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"
22 #include <dali/devel-api/actors/actor-devel.h>
23 #include <dali/devel-api/common/stage.h>
24 #include <dali/integration-api/debug.h>
25 #include <dali/public-api/animation/constraint.h>
26 #include <dali/public-api/animation/constraints.h>
27 #include <dali/public-api/object/type-registry-helper.h>
28 #include <dali/public-api/object/type-registry.h>
29 #include <dali/public-api/render-tasks/render-task-list.h>
30 #include <dali/public-api/rendering/geometry.h>
31 #include <dali/public-api/rendering/renderer.h>
32 #include <dali/public-api/rendering/shader.h>
37 #include <dali-toolkit/devel-api/controls/control-devel.h>
38 #include <dali-toolkit/internal/controls/control/control-data-impl.h>
39 #include <dali-toolkit/internal/controls/control/control-renderers.h>
40 #include <dali-toolkit/internal/graphics/builtin-shader-extern-gen.h>
41 #include <dali-toolkit/public-api/visuals/visual-properties.h>
44 // pixel format / size - set from JSON
45 // 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
46 // default near clip value
47 // 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.
61 // 1st mode, this control has a tree of actors (use Add() to add children) that are rendered and blurred.
62 // mRenderChildrenTask renders children to FB mRenderTargetForRenderingChildren
63 // mHorizBlurTask renders mHorizBlurActor Actor showing FB mRenderTargetForRenderingChildren into FB mRenderTarget2
64 // mVertBlurTask renders mVertBlurActor Actor showing FB mRenderTarget2 into FB mRenderTarget1
65 // mCompositeTask renders mCompositingActor Actor showing FB mRenderTarget1 into FB mRenderTargetForRenderingChildren
67 // 2nd mode, an image is blurred and rendered to a supplied target framebuffer
68 // mHorizBlurTask renders mHorizBlurActor Actor showing mUserInputImage into FB mRenderTarget2
69 // mVertBlurTask renders mVertBlurActor Actor showing mRenderTarget2 into FB mUserOutputRenderTarget
71 // Only this 2nd mode handles ActivateOnce
85 return Toolkit::GaussianBlurView::New();
88 DALI_TYPE_REGISTRATION_BEGIN(Toolkit::GaussianBlurView, Toolkit::Control, Create)
89 DALI_TYPE_REGISTRATION_END()
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 char* const 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;
103 GaussianBlurView::GaussianBlurView()
104 : Control(ControlBehaviour(DISABLE_SIZE_NEGOTIATION | DISABLE_STYLE_CHANGE_SIGNALS)),
105 mNumSamples(GAUSSIAN_BLUR_VIEW_DEFAULT_NUM_SAMPLES),
106 mBlurBellCurveWidth(0.001f),
107 mPixelFormat(GAUSSIAN_BLUR_VIEW_DEFAULT_RENDER_TARGET_PIXEL_FORMAT),
108 mDownsampleWidthScale(GAUSSIAN_BLUR_VIEW_DEFAULT_DOWNSAMPLE_WIDTH_SCALE),
109 mDownsampleHeightScale(GAUSSIAN_BLUR_VIEW_DEFAULT_DOWNSAMPLE_HEIGHT_SCALE),
110 mDownsampledWidth(0.0f),
111 mDownsampledHeight(0.0f),
112 mBlurUserImage(false),
114 mBackgroundColor(Color::BLACK),
115 mTargetSize(Vector2::ZERO),
116 mLastSize(Vector2::ZERO),
117 mChildrenRoot(Actor::New()),
118 mInternalRoot(Actor::New()),
119 mBlurStrengthPropertyIndex(Property::INVALID_INDEX),
122 SetBlurBellCurveWidth(GAUSSIAN_BLUR_VIEW_DEFAULT_BLUR_BELL_CURVE_WIDTH);
125 GaussianBlurView::GaussianBlurView(const unsigned int numSamples,
126 const float blurBellCurveWidth,
127 const Pixel::Format renderTargetPixelFormat,
128 const float downsampleWidthScale,
129 const float downsampleHeightScale,
131 : Control(ControlBehaviour(DISABLE_SIZE_NEGOTIATION | DISABLE_STYLE_CHANGE_SIGNALS)),
132 mNumSamples(numSamples),
133 mBlurBellCurveWidth(0.001f),
134 mPixelFormat(renderTargetPixelFormat),
135 mDownsampleWidthScale(downsampleWidthScale),
136 mDownsampleHeightScale(downsampleHeightScale),
137 mDownsampledWidth(0.0f),
138 mDownsampledHeight(0.0f),
139 mBlurUserImage(blurUserImage),
141 mBackgroundColor(Color::BLACK),
142 mTargetSize(Vector2::ZERO),
143 mLastSize(Vector2::ZERO),
144 mChildrenRoot(Actor::New()),
145 mInternalRoot(Actor::New()),
146 mBlurStrengthPropertyIndex(Property::INVALID_INDEX),
149 SetBlurBellCurveWidth(blurBellCurveWidth);
152 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, const float downsampleWidthScale, const float downsampleHeightScale, bool blurUserImage)
171 GaussianBlurView* impl = new GaussianBlurView(numSamples, blurBellCurveWidth, renderTargetPixelFormat, downsampleWidthScale, downsampleHeightScale, blurUserImage);
173 Dali::Toolkit::GaussianBlurView handle = Dali::Toolkit::GaussianBlurView(*impl);
175 // Second-phase init of the implementation
176 // This can only be done after the CustomActor connection has been made...
182 void GaussianBlurView::SetUserImageAndOutputRenderTarget(Texture inputImage, FrameBuffer outputRenderTarget)
184 // can only do this if the GaussianBlurView object was created with this parameter set
185 DALI_ASSERT_ALWAYS(mBlurUserImage);
187 mUserInputImage = inputImage;
189 SetRendererTexture(mHorizBlurActor.GetRendererAt(0), inputImage);
191 mUserOutputRenderTarget = outputRenderTarget;
194 FrameBuffer GaussianBlurView::GetBlurredRenderTarget() const
196 if(!mUserOutputRenderTarget)
198 return mRenderTargetForRenderingChildren;
201 return mUserOutputRenderTarget;
204 void GaussianBlurView::SetBackgroundColor(const Vector4& color)
206 mBackgroundColor = color;
209 Vector4 GaussianBlurView::GetBackgroundColor() const
211 return mBackgroundColor;
214 ///////////////////////////////////////////////////////////
219 void GaussianBlurView::OnInitialize()
221 // root actor to parent all user added actors, needed to allow us to set that subtree as exclusive for our child render task
222 mChildrenRoot.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
223 mInternalRoot.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
225 //////////////////////////////////////////////////////
228 std::ostringstream fragmentStringStream;
229 fragmentStringStream << "#define NUM_SAMPLES " << mNumSamples << "\n";
230 fragmentStringStream << SHADER_GAUSSIAN_BLUR_VIEW_FRAG;
231 std::string fragmentSource(fragmentStringStream.str());
233 //////////////////////////////////////////////////////
236 // Create an actor for performing a horizontal blur on the texture
237 mHorizBlurActor = Actor::New();
238 mHorizBlurActor.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
240 Renderer renderer = CreateRenderer(BASIC_VERTEX_SOURCE, fragmentSource.c_str());
241 mHorizBlurActor.AddRenderer(renderer);
243 // Create an actor for performing a vertical blur on the texture
244 mVertBlurActor = Actor::New();
245 mVertBlurActor.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
246 renderer = CreateRenderer(BASIC_VERTEX_SOURCE, fragmentSource.c_str());
247 mVertBlurActor.AddRenderer(renderer);
249 // Register a property that the user can control to fade the blur in / out via the GaussianBlurView object
251 mBlurStrengthPropertyIndex = self.RegisterProperty(GAUSSIAN_BLUR_VIEW_STRENGTH_PROPERTY_NAME, GAUSSIAN_BLUR_VIEW_DEFAULT_BLUR_STRENGTH);
253 // Create an image view for compositing the blur and the original child actors render
256 mCompositingActor = Actor::New();
257 mCompositingActor.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
258 mCompositingActor.SetProperty(Actor::Property::OPACITY, GAUSSIAN_BLUR_VIEW_DEFAULT_BLUR_STRENGTH); // ensure alpha is enabled for this object and set default value
259 renderer = CreateRenderer(BASIC_VERTEX_SOURCE, BASIC_FRAGMENT_SOURCE);
260 mCompositingActor.AddRenderer(renderer);
262 Constraint blurStrengthConstraint = Constraint::New<float>(mCompositingActor, Actor::Property::COLOR_ALPHA, EqualToConstraint());
263 blurStrengthConstraint.AddSource(Source(self, mBlurStrengthPropertyIndex));
264 blurStrengthConstraint.Apply();
266 // 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
267 mTargetActor = Actor::New();
268 mTargetActor.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
269 renderer = CreateRenderer(BASIC_VERTEX_SOURCE, BASIC_FRAGMENT_SOURCE);
270 mTargetActor.AddRenderer(renderer);
272 //////////////////////////////////////////////////////
273 // Create cameras for the renders corresponding to the view size
274 mRenderFullSizeCamera = CameraActor::New();
275 mRenderFullSizeCamera.SetInvertYAxis(true);
276 mRenderFullSizeCamera.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
278 //////////////////////////////////////////////////////
279 // Connect to actor tree
280 mInternalRoot.Add(mCompositingActor);
281 mInternalRoot.Add(mTargetActor);
282 mInternalRoot.Add(mRenderFullSizeCamera);
285 //////////////////////////////////////////////////////
286 // Create camera for the renders corresponding to the (potentially downsampled) render targets' size
287 mRenderDownsampledCamera = CameraActor::New();
288 mRenderDownsampledCamera.SetInvertYAxis(true);
289 mRenderDownsampledCamera.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
291 //////////////////////////////////////////////////////
292 // Connect to actor tree
293 Self().Add(mChildrenRoot);
294 mInternalRoot.Add(mHorizBlurActor);
295 mInternalRoot.Add(mVertBlurActor);
296 mInternalRoot.Add(mRenderDownsampledCamera);
298 Self().SetProperty(DevelControl::Property::ACCESSIBILITY_ROLE, Dali::Accessibility::Role::FILLER);
301 void GaussianBlurView::OnSizeSet(const Vector3& targetSize)
303 mTargetSize = Vector2(targetSize);
305 mChildrenRoot.SetProperty(Actor::Property::SIZE, targetSize);
309 mCompositingActor.SetProperty(Actor::Property::SIZE, targetSize);
310 mTargetActor.SetProperty(Actor::Property::SIZE, targetSize);
312 // 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
313 // 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
314 // size, this is the trade off for not being able to modify render target size
315 // Change camera z position based on GaussianBlurView actor height
316 float cameraPosConstraintScale = 0.5f / tanf(ARBITRARY_FIELD_OF_VIEW * 0.5f);
317 mRenderFullSizeCamera.SetProperty(Actor::Property::POSITION_Z, mTargetSize.height * cameraPosConstraintScale);
320 // if we have already activated the blur, need to update render target sizes now to reflect the new size of this actor
327 Control::OnSizeSet(targetSize);
330 void GaussianBlurView::OnChildAdd(Actor& child)
332 if(child != mChildrenRoot && child != mInternalRoot)
334 mChildrenRoot.Add(child);
337 Control::OnChildAdd(child);
340 void GaussianBlurView::OnChildRemove(Actor& child)
342 mChildrenRoot.Remove(child);
344 Control::OnChildRemove(child);
347 void GaussianBlurView::AllocateResources()
349 mLastSize = mTargetSize;
351 // get size of downsampled render targets
352 mDownsampledWidth = mTargetSize.width * mDownsampleWidthScale;
353 mDownsampledHeight = mTargetSize.height * mDownsampleHeightScale;
355 // Create and place a camera for the renders corresponding to the (potentially downsampled) render targets' size
356 mRenderDownsampledCamera.SetFieldOfView(ARBITRARY_FIELD_OF_VIEW);
357 // 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
358 mRenderDownsampledCamera.SetNearClippingPlane(1.0f);
359 mRenderDownsampledCamera.SetAspectRatio(mDownsampledWidth / mDownsampledHeight);
360 mRenderDownsampledCamera.SetType(Dali::Camera::FREE_LOOK); // camera orientation based solely on actor
362 mRenderDownsampledCamera.SetProperty(Actor::Property::POSITION, Vector3(0.0f, 0.0f, ((mDownsampledHeight * 0.5f) / tanf(ARBITRARY_FIELD_OF_VIEW * 0.5f))));
364 // setup for normal operation
367 // Create and place a camera for the children render, corresponding to its render target size
368 mRenderFullSizeCamera.SetFieldOfView(ARBITRARY_FIELD_OF_VIEW);
369 // 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
370 mRenderFullSizeCamera.SetNearClippingPlane(1.0f);
371 mRenderFullSizeCamera.SetAspectRatio(mTargetSize.width / mTargetSize.height);
372 mRenderFullSizeCamera.SetType(Dali::Camera::FREE_LOOK); // camera orientation based solely on actor
374 float cameraPosConstraintScale = 0.5f / tanf(ARBITRARY_FIELD_OF_VIEW * 0.5f);
375 mRenderFullSizeCamera.SetProperty(Actor::Property::POSITION, Vector3(0.0f, 0.0f, mTargetSize.height * cameraPosConstraintScale));
377 // create offscreen buffer of new size to render our child actors to
378 mRenderTargetForRenderingChildren = FrameBuffer::New(mTargetSize.width, mTargetSize.height, FrameBuffer::Attachment::NONE);
379 Texture texture = Texture::New(TextureType::TEXTURE_2D, mPixelFormat, unsigned(mTargetSize.width), unsigned(mTargetSize.height));
380 mRenderTargetForRenderingChildren.AttachColorTexture(texture);
382 // Set actor for performing a horizontal blur
383 SetRendererTexture(mHorizBlurActor.GetRendererAt(0), mRenderTargetForRenderingChildren);
385 // Create offscreen buffer for vert blur pass
386 mRenderTarget1 = FrameBuffer::New(mDownsampledWidth, mDownsampledHeight, FrameBuffer::Attachment::NONE);
387 texture = Texture::New(TextureType::TEXTURE_2D, mPixelFormat, unsigned(mDownsampledWidth), unsigned(mDownsampledHeight));
388 mRenderTarget1.AttachColorTexture(texture);
390 // use the completed blur in the first buffer and composite with the original child actors render
391 SetRendererTexture(mCompositingActor.GetRendererAt(0), mRenderTarget1);
393 // set up target actor for rendering result, i.e. the blurred image
394 SetRendererTexture(mTargetActor.GetRendererAt(0), mRenderTargetForRenderingChildren);
397 // Create offscreen buffer for horiz blur pass
398 mRenderTarget2 = FrameBuffer::New(mDownsampledWidth, mDownsampledHeight, FrameBuffer::Attachment::NONE);
399 Texture texture = Texture::New(TextureType::TEXTURE_2D, mPixelFormat, unsigned(mDownsampledWidth), unsigned(mDownsampledHeight));
400 mRenderTarget2.AttachColorTexture(texture);
402 // size needs to match render target
403 mHorizBlurActor.SetProperty(Actor::Property::SIZE, Vector2(mDownsampledWidth, mDownsampledHeight));
405 // size needs to match render target
406 mVertBlurActor.SetProperty(Actor::Property::SIZE, Vector2(mDownsampledWidth, mDownsampledHeight));
407 SetRendererTexture(mVertBlurActor.GetRendererAt(0), mRenderTarget2);
409 // set gaussian blur up for new sized render targets
410 SetShaderConstants();
413 void GaussianBlurView::CreateRenderTasks()
415 RenderTaskList taskList = Stage::GetCurrent().GetRenderTaskList();
419 // create render task to render our child actors to offscreen buffer
420 mRenderChildrenTask = taskList.CreateTask();
421 mRenderChildrenTask.SetSourceActor(mChildrenRoot);
422 mRenderChildrenTask.SetExclusive(true);
423 mRenderChildrenTask.SetInputEnabled(false);
424 mRenderChildrenTask.SetClearEnabled(true);
425 mRenderChildrenTask.SetClearColor(mBackgroundColor);
427 mRenderChildrenTask.SetCameraActor(mRenderFullSizeCamera);
428 mRenderChildrenTask.SetFrameBuffer(mRenderTargetForRenderingChildren);
432 mRenderChildrenTask.SetRefreshRate(RenderTask::REFRESH_ONCE);
436 // perform a horizontal blur targeting the second buffer
437 mHorizBlurTask = taskList.CreateTask();
438 mHorizBlurTask.SetSourceActor(mHorizBlurActor);
439 mHorizBlurTask.SetExclusive(true);
440 mHorizBlurTask.SetInputEnabled(false);
441 mHorizBlurTask.SetClearEnabled(true);
442 mHorizBlurTask.SetClearColor(mBackgroundColor);
443 mHorizBlurTask.SetCameraActor(mRenderDownsampledCamera);
444 mHorizBlurTask.SetFrameBuffer(mRenderTarget2);
445 if(mRenderOnce || (mRenderOnce && mBlurUserImage))
447 mHorizBlurTask.SetRefreshRate(RenderTask::REFRESH_ONCE);
450 // use the second buffer and perform a horizontal blur targeting the first buffer
451 mVertBlurTask = taskList.CreateTask();
452 mVertBlurTask.SetSourceActor(mVertBlurActor);
453 mVertBlurTask.SetExclusive(true);
454 mVertBlurTask.SetInputEnabled(false);
455 mVertBlurTask.SetClearEnabled(true);
456 mVertBlurTask.SetClearColor(mBackgroundColor);
457 mVertBlurTask.SetCameraActor(mRenderDownsampledCamera);
458 if(mUserOutputRenderTarget)
460 mVertBlurTask.SetFrameBuffer(mUserOutputRenderTarget);
464 mVertBlurTask.SetFrameBuffer(mRenderTarget1);
466 if(mRenderOnce || (mRenderOnce && mBlurUserImage))
468 mVertBlurTask.SetRefreshRate(RenderTask::REFRESH_ONCE);
469 mVertBlurTask.FinishedSignal().Connect(this, &GaussianBlurView::OnRenderTaskFinished);
472 // use the completed blur in the first buffer and composite with the original child actors render
475 mCompositeTask = taskList.CreateTask();
476 mCompositeTask.SetSourceActor(mCompositingActor);
477 mCompositeTask.SetExclusive(true);
478 mCompositeTask.SetInputEnabled(false);
480 mCompositeTask.SetCameraActor(mRenderFullSizeCamera);
481 mCompositeTask.SetFrameBuffer(mRenderTargetForRenderingChildren);
485 mCompositeTask.SetRefreshRate(RenderTask::REFRESH_ONCE);
490 void GaussianBlurView::RemoveRenderTasks()
492 RenderTaskList taskList = Stage::GetCurrent().GetRenderTaskList();
494 taskList.RemoveTask(mRenderChildrenTask);
495 taskList.RemoveTask(mHorizBlurTask);
496 taskList.RemoveTask(mVertBlurTask);
497 taskList.RemoveTask(mCompositeTask);
500 void GaussianBlurView::Activate()
504 // make sure resources are allocated and start the render tasks processing
505 Self().Add(mInternalRoot);
512 void GaussianBlurView::ActivateOnce()
519 void GaussianBlurView::Deactivate()
523 // stop render tasks processing
524 // Note: render target resources are automatically freed since we set the Image::Unused flag
525 mInternalRoot.Unparent();
526 mRenderTargetForRenderingChildren.Reset();
527 mRenderTarget1.Reset();
528 mRenderTarget2.Reset();
535 void GaussianBlurView::SetBlurBellCurveWidth(float blurBellCurveWidth)
537 // a value of zero leads to undefined Gaussian weights, do not allow user to do this
538 mBlurBellCurveWidth = std::max(blurBellCurveWidth, 0.001f);
541 float GaussianBlurView::CalcGaussianWeight(float x)
543 return (1.0f / sqrt(2.0f * Math::PI * mBlurBellCurveWidth)) * exp(-(x * x) / (2.0f * mBlurBellCurveWidth * mBlurBellCurveWidth));
546 void GaussianBlurView::SetShaderConstants()
551 float w, totalWeights;
554 uvOffsets = new Vector2[mNumSamples + 1];
555 weights = new float[mNumSamples + 1];
557 totalWeights = weights[0] = CalcGaussianWeight(0);
558 uvOffsets[0].x = 0.0f;
559 uvOffsets[0].y = 0.0f;
561 for(i = 0; i<mNumSamples >> 1; i++)
563 w = CalcGaussianWeight((float)(i + 1));
564 weights[(i << 1) + 1] = w;
565 weights[(i << 1) + 2] = w;
566 totalWeights += w * 2.0f;
568 // offset texture lookup to between texels, that way the bilinear filter in the texture hardware will average two samples with one lookup
569 ofs = ((float)(i << 1)) + 1.5f;
571 // get offsets from units of pixels into uv coordinates in [0..1]
572 float ofsX = ofs / mDownsampledWidth;
573 float ofsY = ofs / mDownsampledHeight;
574 uvOffsets[(i << 1) + 1].x = ofsX;
575 uvOffsets[(i << 1) + 1].y = ofsY;
577 uvOffsets[(i << 1) + 2].x = -ofsX;
578 uvOffsets[(i << 1) + 2].y = -ofsY;
581 for(i = 0; i < mNumSamples; i++)
583 weights[i] /= totalWeights;
586 // set shader constants
587 Vector2 xAxis(1.0f, 0.0f);
588 Vector2 yAxis(0.0f, 1.0f);
589 for(i = 0; i < mNumSamples; ++i)
591 mHorizBlurActor.RegisterProperty(GetSampleOffsetsPropertyName(i), uvOffsets[i] * xAxis);
592 mHorizBlurActor.RegisterProperty(GetSampleWeightsPropertyName(i), weights[i]);
594 mVertBlurActor.RegisterProperty(GetSampleOffsetsPropertyName(i), uvOffsets[i] * yAxis);
595 mVertBlurActor.RegisterProperty(GetSampleWeightsPropertyName(i), weights[i]);
602 std::string GaussianBlurView::GetSampleOffsetsPropertyName(unsigned int index) const
604 DALI_ASSERT_ALWAYS(index < mNumSamples);
606 std::ostringstream oss;
607 oss << "uSampleOffsets[" << index << "]";
611 std::string GaussianBlurView::GetSampleWeightsPropertyName(unsigned int index) const
613 DALI_ASSERT_ALWAYS(index < mNumSamples);
615 std::ostringstream oss;
616 oss << "uSampleWeights[" << index << "]";
620 Dali::Toolkit::GaussianBlurView::GaussianBlurViewSignal& GaussianBlurView::FinishedSignal()
622 return mFinishedSignal;
625 void GaussianBlurView::OnRenderTaskFinished(Dali::RenderTask& renderTask)
627 Toolkit::GaussianBlurView handle(GetOwner());
628 mFinishedSignal.Emit(handle);
631 } // namespace Internal
632 } // namespace Toolkit