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.RegisterUniqueProperty("blurStrength", 0.f);
152 DevelControl::SetAccessibilityConstructor(self, [](Dali::Actor actor) {
153 return std::make_unique<DevelControl::ControlAccessible>(actor, Dali::Accessibility::Role::FILLER);
157 void SuperBlurView::SetTexture(Texture texture)
159 mInputTexture = texture;
161 if(mTargetSize == Vector2::ZERO)
170 BlurTexture(0, mInputTexture);
171 SetRendererTexture(mRenderers[0], texture);
174 for(; i < mBlurLevels; i++)
176 BlurTexture(i, mBlurredImage[i - 1].GetColorTexture());
177 SetRendererTexture(mRenderers[i], mBlurredImage[i - 1]);
180 SetRendererTexture(mRenderers[i], mBlurredImage[i - 1]);
182 mResourcesCleared = false;
185 Property::Index SuperBlurView::GetBlurStrengthPropertyIndex() const
187 return mBlurStrengthPropertyIndex;
190 void SuperBlurView::SetBlurStrength(float blurStrength)
192 Self().SetProperty(mBlurStrengthPropertyIndex, blurStrength);
195 float SuperBlurView::GetCurrentBlurStrength() const
198 (Self().GetProperty(mBlurStrengthPropertyIndex)).Get(blurStrength);
203 Toolkit::SuperBlurView::SuperBlurViewSignal& SuperBlurView::BlurFinishedSignal()
205 return mBlurFinishedSignal;
208 Texture SuperBlurView::GetBlurredTexture(unsigned int level)
210 DALI_ASSERT_ALWAYS(level > 0 && level <= mBlurLevels);
212 FrameBuffer frameBuffer = mBlurredImage[level - 1];
214 return frameBuffer.GetColorTexture();
217 void SuperBlurView::BlurTexture(unsigned int idx, Texture texture)
219 DALI_ASSERT_ALWAYS(mGaussianBlurView.size() > idx);
220 mGaussianBlurView[idx] = Toolkit::GaussianBlurView::New(GAUSSIAN_BLUR_DEFAULT_NUM_SAMPLES + GAUSSIAN_BLUR_NUM_SAMPLES_INCREMENTATION * idx,
221 GAUSSIAN_BLUR_BELL_CURVE_WIDTH + GAUSSIAN_BLUR_BELL_CURVE_WIDTH_INCREMENTATION * static_cast<float>(idx),
222 GAUSSIAN_BLUR_RENDER_TARGET_PIXEL_FORMAT,
223 GAUSSIAN_BLUR_DOWNSAMPLE_WIDTH_SCALE,
224 GAUSSIAN_BLUR_DOWNSAMPLE_HEIGHT_SCALE,
226 mGaussianBlurView[idx].SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
227 mGaussianBlurView[idx].SetProperty(Actor::Property::SIZE, mTargetSize);
228 Stage::GetCurrent().Add(mGaussianBlurView[idx]);
230 mGaussianBlurView[idx].SetUserImageAndOutputRenderTarget(texture, mBlurredImage[idx]);
232 mGaussianBlurView[idx].ActivateOnce();
233 if(idx == mBlurLevels - 1)
235 mGaussianBlurView[idx].FinishedSignal().Connect(this, &SuperBlurView::OnBlurViewFinished);
239 void SuperBlurView::OnBlurViewFinished(Toolkit::GaussianBlurView blurView)
242 Toolkit::SuperBlurView handle(GetOwner());
243 mBlurFinishedSignal.Emit(handle);
246 void SuperBlurView::ClearBlurResource()
248 if(!mResourcesCleared)
250 DALI_ASSERT_ALWAYS(mGaussianBlurView.size() == mBlurLevels && "must synchronize the GaussianBlurView group if blur levels got changed ");
251 for(unsigned int i = 0; i < mBlurLevels; i++)
253 Stage::GetCurrent().Remove(mGaussianBlurView[i]);
254 mGaussianBlurView[i].Deactivate();
256 mResourcesCleared = true;
260 void SuperBlurView::OnSizeSet(const Vector3& targetSize)
262 if(mTargetSize != Vector2(targetSize))
264 mTargetSize = Vector2(targetSize);
267 for(unsigned int i = 1; i <= mBlurLevels; i++)
269 float exponent = static_cast<float>(i);
271 unsigned int width = mTargetSize.width / std::pow(2.f, exponent);
272 unsigned int height = mTargetSize.height / std::pow(2.f, exponent);
274 mBlurredImage[i - 1] = FrameBuffer::New(width, height, FrameBuffer::Attachment::NONE);
275 Texture texture = Texture::New(TextureType::TEXTURE_2D, GAUSSIAN_BLUR_RENDER_TARGET_PIXEL_FORMAT, unsigned(width), unsigned(height));
276 mBlurredImage[i - 1].AttachColorTexture(texture);
281 SetTexture(mInputTexture);
285 Control::OnSizeSet(targetSize);
288 void SuperBlurView::OnSceneConnection(int depth)
290 if(mTargetSize == Vector2::ZERO)
295 // Exception to the rule, chaining up first ensures visuals have SetOnScene called to create their renderers
296 Control::OnSceneConnection(depth);
300 for(unsigned int i = 0; i < mBlurLevels + 1; i++)
302 mRenderers[i] = CreateRenderer(BASIC_VERTEX_SOURCE, SHADER_SUPER_BLUR_VIEW_FRAG);
303 mRenderers[i].SetProperty(Dali::Renderer::Property::DEPTH_INDEX, (int)i);
304 self.AddRenderer(mRenderers[i]);
308 Renderer renderer = mRenderers[i];
309 Property::Index index = renderer.RegisterUniqueProperty(ALPHA_UNIFORM_NAME, 0.f);
310 Constraint constraint = Constraint::New<float>(renderer, index, ActorOpacityConstraint(mBlurLevels, i - 1));
311 constraint.AddSource(Source(self, mBlurStrengthPropertyIndex));
318 SetRendererTexture(mRenderers[0], mInputTexture);
320 for(; i < mBlurLevels; i++)
322 SetRendererTexture(mRenderers[i], mBlurredImage[i - 1]);
324 SetRendererTexture(mRenderers[i], mBlurredImage[i - 1]);
328 void SuperBlurView::OnSceneDisconnection()
330 for(unsigned int i = 0; i < mBlurLevels + 1; i++)
332 Self().RemoveRenderer(mRenderers[i]);
333 mRenderers[i].Reset();
336 Control::OnSceneDisconnection();
339 Vector3 SuperBlurView::GetNaturalSize()
343 return Vector3(mInputTexture.GetWidth(), mInputTexture.GetHeight(), 0.f);
345 return Vector3::ZERO;
348 void SuperBlurView::SetProperty(BaseObject* object, Property::Index propertyIndex, const Property::Value& value)
350 Toolkit::SuperBlurView superBlurView = Toolkit::SuperBlurView::DownCast(Dali::BaseHandle(object));
354 SuperBlurView& superBlurViewImpl(GetImpl(superBlurView));
356 if(propertyIndex == Toolkit::SuperBlurView::Property::IMAGE_URL)
358 value.Get(superBlurViewImpl.mUrl);
360 PixelData pixels = SyncImageLoader::Load(superBlurViewImpl.mUrl);
364 Texture texture = Texture::New(TextureType::TEXTURE_2D, pixels.GetPixelFormat(), pixels.GetWidth(), pixels.GetHeight());
365 texture.Upload(pixels, 0, 0, 0, 0, pixels.GetWidth(), pixels.GetHeight());
367 superBlurViewImpl.SetTexture(texture);
371 DALI_LOG_ERROR("Cannot create image from property value\n");
377 Property::Value SuperBlurView::GetProperty(BaseObject* object, Property::Index propertyIndex)
379 Property::Value value;
381 Toolkit::SuperBlurView blurView = Toolkit::SuperBlurView::DownCast(Dali::BaseHandle(object));
385 SuperBlurView& superBlurViewImpl(GetImpl(blurView));
387 if(propertyIndex == Toolkit::SuperBlurView::Property::IMAGE_URL)
389 value = superBlurViewImpl.mUrl;
396 } // namespace Internal
398 } // namespace Toolkit