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 "super-blur-view-impl.h"
22 #include <dali/devel-api/common/stage.h>
23 #include <dali/devel-api/scripting/scripting.h>
24 #include <dali/integration-api/debug.h>
25 #include <dali/public-api/animation/constraint.h>
26 #include <dali/public-api/object/property-map.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/rendering/renderer.h>
33 #include <dali-toolkit/devel-api/controls/control-devel.h>
34 #include <dali-toolkit/internal/controls/control/control-data-impl.h>
35 #include <dali-toolkit/internal/controls/control/control-renderers.h>
36 #include <dali-toolkit/internal/graphics/builtin-shader-extern-gen.h>
37 #include <dali-toolkit/internal/visuals/visual-base-impl.h>
38 #include <dali-toolkit/internal/visuals/visual-factory-impl.h>
39 #include <dali-toolkit/public-api/image-loader/sync-image-loader.h>
41 namespace //Unnamed namespace
45 //Todo: make these properties instead of constants
46 const unsigned int GAUSSIAN_BLUR_DEFAULT_NUM_SAMPLES = 11;
47 const unsigned int GAUSSIAN_BLUR_NUM_SAMPLES_INCREMENTATION = 10;
48 const float GAUSSIAN_BLUR_BELL_CURVE_WIDTH = 4.5f;
49 const float GAUSSIAN_BLUR_BELL_CURVE_WIDTH_INCREMENTATION = 5.f;
50 const Pixel::Format GAUSSIAN_BLUR_RENDER_TARGET_PIXEL_FORMAT = Pixel::RGBA8888;
51 const float GAUSSIAN_BLUR_DOWNSAMPLE_WIDTH_SCALE = 0.5f;
52 const float GAUSSIAN_BLUR_DOWNSAMPLE_HEIGHT_SCALE = 0.5f;
54 const char* ALPHA_UNIFORM_NAME("uAlpha");
57 * The constraint is used to blend the group of blurred images continuously with a unified blur strength property value which ranges from zero to one.
59 struct ActorOpacityConstraint
61 ActorOpacityConstraint(int totalImageNum, int currentImageIdx)
63 float rangeLength = 1.f / static_cast<float>(totalImageNum);
64 float index = static_cast<float>(currentImageIdx);
65 mRange = Vector2(index * rangeLength, (index + 1.f) * rangeLength);
68 void operator()(float& current, const PropertyInputContainer& inputs)
70 float blurStrength = inputs[0]->GetFloat();
71 if(blurStrength < mRange.x)
75 else if(blurStrength > mRange.y)
81 current = (blurStrength - mRange.x) / (mRange.y - mRange.x);
98 const unsigned int DEFAULT_BLUR_LEVEL(5u); ///< The default blur level when creating SuperBlurView from the type registry
102 return Toolkit::SuperBlurView::New(DEFAULT_BLUR_LEVEL);
105 // Setup properties, signals and actions using the type-registry.
106 DALI_TYPE_REGISTRATION_BEGIN(Toolkit::SuperBlurView, Toolkit::Control, Create)
108 DALI_PROPERTY_REGISTRATION(Toolkit, SuperBlurView, "imageUrl", STRING, IMAGE_URL)
110 DALI_TYPE_REGISTRATION_END()
112 } // unnamed namespace
114 SuperBlurView::SuperBlurView(unsigned int blurLevels)
115 : Control(ControlBehaviour(DISABLE_SIZE_NEGOTIATION | DISABLE_STYLE_CHANGE_SIGNALS)),
116 mTargetSize(Vector2::ZERO),
117 mBlurStrengthPropertyIndex(Property::INVALID_INDEX),
118 mBlurLevels(blurLevels),
119 mResourcesCleared(true)
121 DALI_ASSERT_ALWAYS(mBlurLevels > 0 && " Minimal blur level is one, otherwise no blur is needed");
122 mGaussianBlurView.assign(blurLevels, Toolkit::GaussianBlurView());
123 mBlurredImage.assign(blurLevels, FrameBuffer());
124 mRenderers.assign(blurLevels + 1, Dali::Renderer());
127 SuperBlurView::~SuperBlurView()
131 Toolkit::SuperBlurView SuperBlurView::New(unsigned int blurLevels)
133 //Create the implementation
134 IntrusivePtr<SuperBlurView> superBlurView(new SuperBlurView(blurLevels));
136 //Pass ownership to CustomActor via derived handle
137 Toolkit::SuperBlurView handle(*superBlurView);
139 // Second-phase init of the implementation
140 // This can only be done after the CustomActor connection has been made...
141 superBlurView->Initialize();
146 void SuperBlurView::OnInitialize()
150 mBlurStrengthPropertyIndex = self.RegisterProperty("blurStrength", 0.f);
152 DevelControl::SetAccessibilityConstructor(self, [](Dali::Actor actor) {
153 return std::unique_ptr<Dali::Accessibility::Accessible>(
154 new DevelControl::ControlAccessible(actor, Dali::Accessibility::Role::FILLER));
158 void SuperBlurView::SetTexture(Texture texture)
160 mInputTexture = texture;
162 if(mTargetSize == Vector2::ZERO)
171 BlurTexture(0, mInputTexture);
172 SetRendererTexture(mRenderers[0], texture);
175 for(; i < mBlurLevels; i++)
177 BlurTexture(i, mBlurredImage[i - 1].GetColorTexture());
178 SetRendererTexture(mRenderers[i], mBlurredImage[i - 1]);
181 SetRendererTexture(mRenderers[i], mBlurredImage[i - 1]);
183 mResourcesCleared = false;
186 Property::Index SuperBlurView::GetBlurStrengthPropertyIndex() const
188 return mBlurStrengthPropertyIndex;
191 void SuperBlurView::SetBlurStrength(float blurStrength)
193 Self().SetProperty(mBlurStrengthPropertyIndex, blurStrength);
196 float SuperBlurView::GetCurrentBlurStrength() const
199 (Self().GetProperty(mBlurStrengthPropertyIndex)).Get(blurStrength);
204 Toolkit::SuperBlurView::SuperBlurViewSignal& SuperBlurView::BlurFinishedSignal()
206 return mBlurFinishedSignal;
209 Texture SuperBlurView::GetBlurredTexture(unsigned int level)
211 DALI_ASSERT_ALWAYS(level > 0 && level <= mBlurLevels);
213 FrameBuffer frameBuffer = mBlurredImage[level - 1];
215 return frameBuffer.GetColorTexture();
218 void SuperBlurView::BlurTexture(unsigned int idx, Texture texture)
220 DALI_ASSERT_ALWAYS(mGaussianBlurView.size() > idx);
221 mGaussianBlurView[idx] = Toolkit::GaussianBlurView::New(GAUSSIAN_BLUR_DEFAULT_NUM_SAMPLES + GAUSSIAN_BLUR_NUM_SAMPLES_INCREMENTATION * idx,
222 GAUSSIAN_BLUR_BELL_CURVE_WIDTH + GAUSSIAN_BLUR_BELL_CURVE_WIDTH_INCREMENTATION * static_cast<float>(idx),
223 GAUSSIAN_BLUR_RENDER_TARGET_PIXEL_FORMAT,
224 GAUSSIAN_BLUR_DOWNSAMPLE_WIDTH_SCALE,
225 GAUSSIAN_BLUR_DOWNSAMPLE_HEIGHT_SCALE,
227 mGaussianBlurView[idx].SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
228 mGaussianBlurView[idx].SetProperty(Actor::Property::SIZE, mTargetSize);
229 Stage::GetCurrent().Add(mGaussianBlurView[idx]);
231 mGaussianBlurView[idx].SetUserImageAndOutputRenderTarget(texture, mBlurredImage[idx]);
233 mGaussianBlurView[idx].ActivateOnce();
234 if(idx == mBlurLevels - 1)
236 mGaussianBlurView[idx].FinishedSignal().Connect(this, &SuperBlurView::OnBlurViewFinished);
240 void SuperBlurView::OnBlurViewFinished(Toolkit::GaussianBlurView blurView)
243 Toolkit::SuperBlurView handle(GetOwner());
244 mBlurFinishedSignal.Emit(handle);
247 void SuperBlurView::ClearBlurResource()
249 if(!mResourcesCleared)
251 DALI_ASSERT_ALWAYS(mGaussianBlurView.size() == mBlurLevels && "must synchronize the GaussianBlurView group if blur levels got changed ");
252 for(unsigned int i = 0; i < mBlurLevels; i++)
254 Stage::GetCurrent().Remove(mGaussianBlurView[i]);
255 mGaussianBlurView[i].Deactivate();
257 mResourcesCleared = true;
261 void SuperBlurView::OnSizeSet(const Vector3& targetSize)
263 if(mTargetSize != Vector2(targetSize))
265 mTargetSize = Vector2(targetSize);
268 for(unsigned int i = 1; i <= mBlurLevels; i++)
270 float exponent = static_cast<float>(i);
272 unsigned int width = mTargetSize.width / std::pow(2.f, exponent);
273 unsigned int height = mTargetSize.height / std::pow(2.f, exponent);
275 mBlurredImage[i - 1] = FrameBuffer::New(width, height, FrameBuffer::Attachment::NONE);
276 Texture texture = Texture::New(TextureType::TEXTURE_2D, GAUSSIAN_BLUR_RENDER_TARGET_PIXEL_FORMAT, unsigned(width), unsigned(height));
277 mBlurredImage[i - 1].AttachColorTexture(texture);
282 SetTexture(mInputTexture);
286 Control::OnSizeSet(targetSize);
289 void SuperBlurView::OnSceneConnection(int depth)
291 if(mTargetSize == Vector2::ZERO)
296 // Exception to the rule, chaining up first ensures visuals have SetOnScene called to create their renderers
297 Control::OnSceneConnection(depth);
301 for(unsigned int i = 0; i < mBlurLevels + 1; i++)
303 mRenderers[i] = CreateRenderer(BASIC_VERTEX_SOURCE, SHADER_SUPER_BLUR_VIEW_FRAG);
304 mRenderers[i].SetProperty(Dali::Renderer::Property::DEPTH_INDEX, (int)i);
305 self.AddRenderer(mRenderers[i]);
309 Renderer renderer = mRenderers[i];
310 Property::Index index = renderer.RegisterProperty(ALPHA_UNIFORM_NAME, 0.f);
311 Constraint constraint = Constraint::New<float>(renderer, index, ActorOpacityConstraint(mBlurLevels, i - 1));
312 constraint.AddSource(Source(self, mBlurStrengthPropertyIndex));
319 SetRendererTexture(mRenderers[0], mInputTexture);
321 for(; i < mBlurLevels; i++)
323 SetRendererTexture(mRenderers[i], mBlurredImage[i - 1]);
325 SetRendererTexture(mRenderers[i], mBlurredImage[i - 1]);
329 void SuperBlurView::OnSceneDisconnection()
331 for(unsigned int i = 0; i < mBlurLevels + 1; i++)
333 Self().RemoveRenderer(mRenderers[i]);
334 mRenderers[i].Reset();
337 Control::OnSceneDisconnection();
340 Vector3 SuperBlurView::GetNaturalSize()
344 return Vector3(mInputTexture.GetWidth(), mInputTexture.GetHeight(), 0.f);
346 return Vector3::ZERO;
349 void SuperBlurView::SetProperty(BaseObject* object, Property::Index propertyIndex, const Property::Value& value)
351 Toolkit::SuperBlurView superBlurView = Toolkit::SuperBlurView::DownCast(Dali::BaseHandle(object));
355 SuperBlurView& superBlurViewImpl(GetImpl(superBlurView));
357 if(propertyIndex == Toolkit::SuperBlurView::Property::IMAGE_URL)
359 value.Get(superBlurViewImpl.mUrl);
361 PixelData pixels = SyncImageLoader::Load(superBlurViewImpl.mUrl);
365 Texture texture = Texture::New(TextureType::TEXTURE_2D, pixels.GetPixelFormat(), pixels.GetWidth(), pixels.GetHeight());
366 texture.Upload(pixels, 0, 0, 0, 0, pixels.GetWidth(), pixels.GetHeight());
368 superBlurViewImpl.SetTexture(texture);
372 DALI_LOG_ERROR("Cannot create image from property value\n");
378 Property::Value SuperBlurView::GetProperty(BaseObject* object, Property::Index propertyIndex)
380 Property::Value value;
382 Toolkit::SuperBlurView blurView = Toolkit::SuperBlurView::DownCast(Dali::BaseHandle(object));
386 SuperBlurView& superBlurViewImpl(GetImpl(blurView));
388 if(propertyIndex == Toolkit::SuperBlurView::Property::IMAGE_URL)
390 value = superBlurViewImpl.mUrl;
397 } // namespace Internal
399 } // namespace Toolkit