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 self.SetProperty(DevelControl::Property::ACCESSIBILITY_ROLE, Dali::Accessibility::Role::FILLER);
155 void SuperBlurView::SetTexture(Texture texture)
157 mInputTexture = texture;
159 if(mTargetSize == Vector2::ZERO)
168 BlurTexture(0, mInputTexture);
169 SetRendererTexture(mRenderers[0], texture);
172 for(; i < mBlurLevels; i++)
174 BlurTexture(i, mBlurredImage[i - 1].GetColorTexture());
175 SetRendererTexture(mRenderers[i], mBlurredImage[i - 1]);
178 SetRendererTexture(mRenderers[i], mBlurredImage[i - 1]);
180 mResourcesCleared = false;
183 Property::Index SuperBlurView::GetBlurStrengthPropertyIndex() const
185 return mBlurStrengthPropertyIndex;
188 void SuperBlurView::SetBlurStrength(float blurStrength)
190 Self().SetProperty(mBlurStrengthPropertyIndex, blurStrength);
193 float SuperBlurView::GetCurrentBlurStrength() const
196 (Self().GetProperty(mBlurStrengthPropertyIndex)).Get(blurStrength);
201 Toolkit::SuperBlurView::SuperBlurViewSignal& SuperBlurView::BlurFinishedSignal()
203 return mBlurFinishedSignal;
206 Texture SuperBlurView::GetBlurredTexture(unsigned int level)
208 DALI_ASSERT_ALWAYS(level > 0 && level <= mBlurLevels);
210 FrameBuffer frameBuffer = mBlurredImage[level - 1];
212 return frameBuffer.GetColorTexture();
215 void SuperBlurView::BlurTexture(unsigned int idx, Texture texture)
217 DALI_ASSERT_ALWAYS(mGaussianBlurView.size() > idx);
218 mGaussianBlurView[idx] = Toolkit::GaussianBlurView::New(GAUSSIAN_BLUR_DEFAULT_NUM_SAMPLES + GAUSSIAN_BLUR_NUM_SAMPLES_INCREMENTATION * idx,
219 GAUSSIAN_BLUR_BELL_CURVE_WIDTH + GAUSSIAN_BLUR_BELL_CURVE_WIDTH_INCREMENTATION * static_cast<float>(idx),
220 GAUSSIAN_BLUR_RENDER_TARGET_PIXEL_FORMAT,
221 GAUSSIAN_BLUR_DOWNSAMPLE_WIDTH_SCALE,
222 GAUSSIAN_BLUR_DOWNSAMPLE_HEIGHT_SCALE,
224 mGaussianBlurView[idx].SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
225 mGaussianBlurView[idx].SetProperty(Actor::Property::SIZE, mTargetSize);
226 Stage::GetCurrent().Add(mGaussianBlurView[idx]);
228 mGaussianBlurView[idx].SetUserImageAndOutputRenderTarget(texture, mBlurredImage[idx]);
230 mGaussianBlurView[idx].ActivateOnce();
231 if(idx == mBlurLevels - 1)
233 mGaussianBlurView[idx].FinishedSignal().Connect(this, &SuperBlurView::OnBlurViewFinished);
237 void SuperBlurView::OnBlurViewFinished(Toolkit::GaussianBlurView blurView)
240 Toolkit::SuperBlurView handle(GetOwner());
241 mBlurFinishedSignal.Emit(handle);
244 void SuperBlurView::ClearBlurResource()
246 if(!mResourcesCleared)
248 DALI_ASSERT_ALWAYS(mGaussianBlurView.size() == mBlurLevels && "must synchronize the GaussianBlurView group if blur levels got changed ");
249 for(unsigned int i = 0; i < mBlurLevels; i++)
251 Stage::GetCurrent().Remove(mGaussianBlurView[i]);
252 mGaussianBlurView[i].Deactivate();
254 mResourcesCleared = true;
258 void SuperBlurView::OnSizeSet(const Vector3& targetSize)
260 if(mTargetSize != Vector2(targetSize))
262 mTargetSize = Vector2(targetSize);
265 for(unsigned int i = 1; i <= mBlurLevels; i++)
267 float exponent = static_cast<float>(i);
269 unsigned int width = mTargetSize.width / std::pow(2.f, exponent);
270 unsigned int height = mTargetSize.height / std::pow(2.f, exponent);
272 mBlurredImage[i - 1] = FrameBuffer::New(width, height, FrameBuffer::Attachment::NONE);
273 Texture texture = Texture::New(TextureType::TEXTURE_2D, GAUSSIAN_BLUR_RENDER_TARGET_PIXEL_FORMAT, unsigned(width), unsigned(height));
274 mBlurredImage[i - 1].AttachColorTexture(texture);
279 SetTexture(mInputTexture);
283 Control::OnSizeSet(targetSize);
286 void SuperBlurView::OnSceneConnection(int depth)
288 if(mTargetSize == Vector2::ZERO)
293 // Exception to the rule, chaining up first ensures visuals have SetOnScene called to create their renderers
294 Control::OnSceneConnection(depth);
298 for(unsigned int i = 0; i < mBlurLevels + 1; i++)
300 mRenderers[i] = CreateRenderer(BASIC_VERTEX_SOURCE, SHADER_SUPER_BLUR_VIEW_FRAG);
301 mRenderers[i].SetProperty(Dali::Renderer::Property::DEPTH_INDEX, (int)i);
302 self.AddRenderer(mRenderers[i]);
306 Renderer renderer = mRenderers[i];
307 Property::Index index = renderer.RegisterUniqueProperty(ALPHA_UNIFORM_NAME, 0.f);
308 Constraint constraint = Constraint::New<float>(renderer, index, ActorOpacityConstraint(mBlurLevels, i - 1));
309 constraint.AddSource(Source(self, mBlurStrengthPropertyIndex));
316 SetRendererTexture(mRenderers[0], mInputTexture);
318 for(; i < mBlurLevels; i++)
320 SetRendererTexture(mRenderers[i], mBlurredImage[i - 1]);
322 SetRendererTexture(mRenderers[i], mBlurredImage[i - 1]);
326 void SuperBlurView::OnSceneDisconnection()
328 for(unsigned int i = 0; i < mBlurLevels + 1; i++)
330 Self().RemoveRenderer(mRenderers[i]);
331 mRenderers[i].Reset();
334 Control::OnSceneDisconnection();
337 Vector3 SuperBlurView::GetNaturalSize()
341 return Vector3(mInputTexture.GetWidth(), mInputTexture.GetHeight(), 0.f);
343 return Vector3::ZERO;
346 void SuperBlurView::SetProperty(BaseObject* object, Property::Index propertyIndex, const Property::Value& value)
348 Toolkit::SuperBlurView superBlurView = Toolkit::SuperBlurView::DownCast(Dali::BaseHandle(object));
352 SuperBlurView& superBlurViewImpl(GetImpl(superBlurView));
354 if(propertyIndex == Toolkit::SuperBlurView::Property::IMAGE_URL)
356 value.Get(superBlurViewImpl.mUrl);
358 PixelData pixels = SyncImageLoader::Load(superBlurViewImpl.mUrl);
362 Texture texture = Texture::New(TextureType::TEXTURE_2D, pixels.GetPixelFormat(), pixels.GetWidth(), pixels.GetHeight());
363 texture.Upload(pixels, 0, 0, 0, 0, pixels.GetWidth(), pixels.GetHeight());
365 superBlurViewImpl.SetTexture(texture);
369 DALI_LOG_ERROR("Cannot create image from property value\n");
375 Property::Value SuperBlurView::GetProperty(BaseObject* object, Property::Index propertyIndex)
377 Property::Value value;
379 Toolkit::SuperBlurView blurView = Toolkit::SuperBlurView::DownCast(Dali::BaseHandle(object));
383 SuperBlurView& superBlurViewImpl(GetImpl(blurView));
385 if(propertyIndex == Toolkit::SuperBlurView::Property::IMAGE_URL)
387 value = superBlurViewImpl.mUrl;
394 } // namespace Internal
396 } // namespace Toolkit