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 DevelControl::SetAccessibilityConstructor(Self(), [](Dali::Actor actor) {
299 return std::make_unique<DevelControl::ControlAccessible>(actor, Dali::Accessibility::Role::FILLER);
303 void GaussianBlurView::OnSizeSet(const Vector3& targetSize)
305 mTargetSize = Vector2(targetSize);
307 mChildrenRoot.SetProperty(Actor::Property::SIZE, targetSize);
311 mCompositingActor.SetProperty(Actor::Property::SIZE, targetSize);
312 mTargetActor.SetProperty(Actor::Property::SIZE, targetSize);
314 // 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
315 // 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
316 // size, this is the trade off for not being able to modify render target size
317 // Change camera z position based on GaussianBlurView actor height
318 float cameraPosConstraintScale = 0.5f / tanf(ARBITRARY_FIELD_OF_VIEW * 0.5f);
319 mRenderFullSizeCamera.SetProperty(Actor::Property::POSITION_Z, mTargetSize.height * cameraPosConstraintScale);
322 // if we have already activated the blur, need to update render target sizes now to reflect the new size of this actor
329 Control::OnSizeSet(targetSize);
332 void GaussianBlurView::OnChildAdd(Actor& child)
334 if(child != mChildrenRoot && child != mInternalRoot)
336 mChildrenRoot.Add(child);
339 Control::OnChildAdd(child);
342 void GaussianBlurView::OnChildRemove(Actor& child)
344 mChildrenRoot.Remove(child);
346 Control::OnChildRemove(child);
349 void GaussianBlurView::AllocateResources()
351 mLastSize = mTargetSize;
353 // get size of downsampled render targets
354 mDownsampledWidth = mTargetSize.width * mDownsampleWidthScale;
355 mDownsampledHeight = mTargetSize.height * mDownsampleHeightScale;
357 // Create and place a camera for the renders corresponding to the (potentially downsampled) render targets' size
358 mRenderDownsampledCamera.SetFieldOfView(ARBITRARY_FIELD_OF_VIEW);
359 // 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
360 mRenderDownsampledCamera.SetNearClippingPlane(1.0f);
361 mRenderDownsampledCamera.SetAspectRatio(mDownsampledWidth / mDownsampledHeight);
362 mRenderDownsampledCamera.SetType(Dali::Camera::FREE_LOOK); // camera orientation based solely on actor
364 mRenderDownsampledCamera.SetProperty(Actor::Property::POSITION, Vector3(0.0f, 0.0f, ((mDownsampledHeight * 0.5f) / tanf(ARBITRARY_FIELD_OF_VIEW * 0.5f))));
366 // setup for normal operation
369 // Create and place a camera for the children render, corresponding to its render target size
370 mRenderFullSizeCamera.SetFieldOfView(ARBITRARY_FIELD_OF_VIEW);
371 // 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
372 mRenderFullSizeCamera.SetNearClippingPlane(1.0f);
373 mRenderFullSizeCamera.SetAspectRatio(mTargetSize.width / mTargetSize.height);
374 mRenderFullSizeCamera.SetType(Dali::Camera::FREE_LOOK); // camera orientation based solely on actor
376 float cameraPosConstraintScale = 0.5f / tanf(ARBITRARY_FIELD_OF_VIEW * 0.5f);
377 mRenderFullSizeCamera.SetProperty(Actor::Property::POSITION, Vector3(0.0f, 0.0f, mTargetSize.height * cameraPosConstraintScale));
379 // create offscreen buffer of new size to render our child actors to
380 mRenderTargetForRenderingChildren = FrameBuffer::New(mTargetSize.width, mTargetSize.height, FrameBuffer::Attachment::NONE);
381 Texture texture = Texture::New(TextureType::TEXTURE_2D, mPixelFormat, unsigned(mTargetSize.width), unsigned(mTargetSize.height));
382 mRenderTargetForRenderingChildren.AttachColorTexture(texture);
384 // Set actor for performing a horizontal blur
385 SetRendererTexture(mHorizBlurActor.GetRendererAt(0), mRenderTargetForRenderingChildren);
387 // Create offscreen buffer for vert blur pass
388 mRenderTarget1 = FrameBuffer::New(mDownsampledWidth, mDownsampledHeight, FrameBuffer::Attachment::NONE);
389 texture = Texture::New(TextureType::TEXTURE_2D, mPixelFormat, unsigned(mDownsampledWidth), unsigned(mDownsampledHeight));
390 mRenderTarget1.AttachColorTexture(texture);
392 // use the completed blur in the first buffer and composite with the original child actors render
393 SetRendererTexture(mCompositingActor.GetRendererAt(0), mRenderTarget1);
395 // set up target actor for rendering result, i.e. the blurred image
396 SetRendererTexture(mTargetActor.GetRendererAt(0), mRenderTargetForRenderingChildren);
399 // Create offscreen buffer for horiz blur pass
400 mRenderTarget2 = FrameBuffer::New(mDownsampledWidth, mDownsampledHeight, FrameBuffer::Attachment::NONE);
401 Texture texture = Texture::New(TextureType::TEXTURE_2D, mPixelFormat, unsigned(mDownsampledWidth), unsigned(mDownsampledHeight));
402 mRenderTarget2.AttachColorTexture(texture);
404 // size needs to match render target
405 mHorizBlurActor.SetProperty(Actor::Property::SIZE, Vector2(mDownsampledWidth, mDownsampledHeight));
407 // size needs to match render target
408 mVertBlurActor.SetProperty(Actor::Property::SIZE, Vector2(mDownsampledWidth, mDownsampledHeight));
409 SetRendererTexture(mVertBlurActor.GetRendererAt(0), mRenderTarget2);
411 // set gaussian blur up for new sized render targets
412 SetShaderConstants();
415 void GaussianBlurView::CreateRenderTasks()
417 RenderTaskList taskList = Stage::GetCurrent().GetRenderTaskList();
421 // create render task to render our child actors to offscreen buffer
422 mRenderChildrenTask = taskList.CreateTask();
423 mRenderChildrenTask.SetSourceActor(mChildrenRoot);
424 mRenderChildrenTask.SetExclusive(true);
425 mRenderChildrenTask.SetInputEnabled(false);
426 mRenderChildrenTask.SetClearEnabled(true);
427 mRenderChildrenTask.SetClearColor(mBackgroundColor);
429 mRenderChildrenTask.SetCameraActor(mRenderFullSizeCamera);
430 mRenderChildrenTask.SetFrameBuffer(mRenderTargetForRenderingChildren);
434 mRenderChildrenTask.SetRefreshRate(RenderTask::REFRESH_ONCE);
438 // perform a horizontal blur targeting the second buffer
439 mHorizBlurTask = taskList.CreateTask();
440 mHorizBlurTask.SetSourceActor(mHorizBlurActor);
441 mHorizBlurTask.SetExclusive(true);
442 mHorizBlurTask.SetInputEnabled(false);
443 mHorizBlurTask.SetClearEnabled(true);
444 mHorizBlurTask.SetClearColor(mBackgroundColor);
445 mHorizBlurTask.SetCameraActor(mRenderDownsampledCamera);
446 mHorizBlurTask.SetFrameBuffer(mRenderTarget2);
447 if(mRenderOnce || (mRenderOnce && mBlurUserImage))
449 mHorizBlurTask.SetRefreshRate(RenderTask::REFRESH_ONCE);
452 // use the second buffer and perform a horizontal blur targeting the first buffer
453 mVertBlurTask = taskList.CreateTask();
454 mVertBlurTask.SetSourceActor(mVertBlurActor);
455 mVertBlurTask.SetExclusive(true);
456 mVertBlurTask.SetInputEnabled(false);
457 mVertBlurTask.SetClearEnabled(true);
458 mVertBlurTask.SetClearColor(mBackgroundColor);
459 mVertBlurTask.SetCameraActor(mRenderDownsampledCamera);
460 if(mUserOutputRenderTarget)
462 mVertBlurTask.SetFrameBuffer(mUserOutputRenderTarget);
466 mVertBlurTask.SetFrameBuffer(mRenderTarget1);
468 if(mRenderOnce || (mRenderOnce && mBlurUserImage))
470 mVertBlurTask.SetRefreshRate(RenderTask::REFRESH_ONCE);
471 mVertBlurTask.FinishedSignal().Connect(this, &GaussianBlurView::OnRenderTaskFinished);
474 // use the completed blur in the first buffer and composite with the original child actors render
477 mCompositeTask = taskList.CreateTask();
478 mCompositeTask.SetSourceActor(mCompositingActor);
479 mCompositeTask.SetExclusive(true);
480 mCompositeTask.SetInputEnabled(false);
482 mCompositeTask.SetCameraActor(mRenderFullSizeCamera);
483 mCompositeTask.SetFrameBuffer(mRenderTargetForRenderingChildren);
487 mCompositeTask.SetRefreshRate(RenderTask::REFRESH_ONCE);
492 void GaussianBlurView::RemoveRenderTasks()
494 RenderTaskList taskList = Stage::GetCurrent().GetRenderTaskList();
496 taskList.RemoveTask(mRenderChildrenTask);
497 taskList.RemoveTask(mHorizBlurTask);
498 taskList.RemoveTask(mVertBlurTask);
499 taskList.RemoveTask(mCompositeTask);
502 void GaussianBlurView::Activate()
506 // make sure resources are allocated and start the render tasks processing
507 Self().Add(mInternalRoot);
514 void GaussianBlurView::ActivateOnce()
521 void GaussianBlurView::Deactivate()
525 // stop render tasks processing
526 // Note: render target resources are automatically freed since we set the Image::Unused flag
527 mInternalRoot.Unparent();
528 mRenderTargetForRenderingChildren.Reset();
529 mRenderTarget1.Reset();
530 mRenderTarget2.Reset();
537 void GaussianBlurView::SetBlurBellCurveWidth(float blurBellCurveWidth)
539 // a value of zero leads to undefined Gaussian weights, do not allow user to do this
540 mBlurBellCurveWidth = std::max(blurBellCurveWidth, 0.001f);
543 float GaussianBlurView::CalcGaussianWeight(float x)
545 return (1.0f / sqrt(2.0f * Math::PI * mBlurBellCurveWidth)) * exp(-(x * x) / (2.0f * mBlurBellCurveWidth * mBlurBellCurveWidth));
548 void GaussianBlurView::SetShaderConstants()
553 float w, totalWeights;
556 uvOffsets = new Vector2[mNumSamples + 1];
557 weights = new float[mNumSamples + 1];
559 totalWeights = weights[0] = CalcGaussianWeight(0);
560 uvOffsets[0].x = 0.0f;
561 uvOffsets[0].y = 0.0f;
563 for(i = 0; i<mNumSamples >> 1; i++)
565 w = CalcGaussianWeight((float)(i + 1));
566 weights[(i << 1) + 1] = w;
567 weights[(i << 1) + 2] = w;
568 totalWeights += w * 2.0f;
570 // offset texture lookup to between texels, that way the bilinear filter in the texture hardware will average two samples with one lookup
571 ofs = ((float)(i << 1)) + 1.5f;
573 // get offsets from units of pixels into uv coordinates in [0..1]
574 float ofsX = ofs / mDownsampledWidth;
575 float ofsY = ofs / mDownsampledHeight;
576 uvOffsets[(i << 1) + 1].x = ofsX;
577 uvOffsets[(i << 1) + 1].y = ofsY;
579 uvOffsets[(i << 1) + 2].x = -ofsX;
580 uvOffsets[(i << 1) + 2].y = -ofsY;
583 for(i = 0; i < mNumSamples; i++)
585 weights[i] /= totalWeights;
588 // set shader constants
589 Vector2 xAxis(1.0f, 0.0f);
590 Vector2 yAxis(0.0f, 1.0f);
591 for(i = 0; i < mNumSamples; ++i)
593 mHorizBlurActor.RegisterProperty(GetSampleOffsetsPropertyName(i), uvOffsets[i] * xAxis);
594 mHorizBlurActor.RegisterProperty(GetSampleWeightsPropertyName(i), weights[i]);
596 mVertBlurActor.RegisterProperty(GetSampleOffsetsPropertyName(i), uvOffsets[i] * yAxis);
597 mVertBlurActor.RegisterProperty(GetSampleWeightsPropertyName(i), weights[i]);
604 std::string GaussianBlurView::GetSampleOffsetsPropertyName(unsigned int index) const
606 DALI_ASSERT_ALWAYS(index < mNumSamples);
608 std::ostringstream oss;
609 oss << "uSampleOffsets[" << index << "]";
613 std::string GaussianBlurView::GetSampleWeightsPropertyName(unsigned int index) const
615 DALI_ASSERT_ALWAYS(index < mNumSamples);
617 std::ostringstream oss;
618 oss << "uSampleWeights[" << index << "]";
622 Dali::Toolkit::GaussianBlurView::GaussianBlurViewSignal& GaussianBlurView::FinishedSignal()
624 return mFinishedSignal;
627 void GaussianBlurView::OnRenderTaskFinished(Dali::RenderTask& renderTask)
629 Toolkit::GaussianBlurView handle(GetOwner());
630 mFinishedSignal.Emit(handle);
633 } // namespace Internal
634 } // namespace Toolkit