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 "effects-view-impl.h"
22 #include <dali/devel-api/common/stage.h>
23 #include <dali/public-api/animation/constraint.h>
24 #include <dali/public-api/animation/constraints.h>
25 #include <dali/public-api/object/property-map.h>
26 #include <dali/public-api/object/property.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/renderer.h>
33 #include <dali-toolkit/devel-api/controls/control-depth-index-ranges.h>
34 #include <dali-toolkit/devel-api/controls/control-devel.h>
35 #include <dali-toolkit/internal/controls/control/control-data-impl.h>
36 #include <dali-toolkit/internal/controls/control/control-renderers.h>
37 #include <dali-toolkit/internal/filters/blur-two-pass-filter.h>
38 #include <dali-toolkit/internal/filters/emboss-filter.h>
39 #include <dali-toolkit/internal/filters/spread-filter.h>
40 #include <dali-toolkit/internal/graphics/builtin-shader-extern-gen.h>
50 Dali::BaseHandle Create()
52 return EffectsView::New();
55 DALI_TYPE_REGISTRATION_BEGIN(Toolkit::EffectsView, Toolkit::Control, Create)
56 DALI_PROPERTY_REGISTRATION(Toolkit, EffectsView, "effectSize", INTEGER, EFFECT_SIZE)
57 DALI_ANIMATABLE_PROPERTY_REGISTRATION(Toolkit, EffectsView, "effectOffset", VECTOR3, EFFECT_OFFSET)
58 DALI_ANIMATABLE_PROPERTY_REGISTRATION_WITH_DEFAULT(Toolkit, EffectsView, "effectColor", Color::WHITE, EFFECT_COLOR)
59 DALI_TYPE_REGISTRATION_END()
61 const Pixel::Format EFFECTS_VIEW_DEFAULT_PIXEL_FORMAT = Pixel::RGBA8888;
62 const float ARBITRARY_FIELD_OF_VIEW = Math::PI / 4.0f;
63 const Vector4 EFFECTS_VIEW_DEFAULT_BACKGROUND_COLOR(0.0f, 0.0f, 0.0f, 0.0);
64 const bool EFFECTS_VIEW_REFRESH_ON_DEMAND(false);
67 const float BLUR_KERNEL0[] = {12.0f/16.0f,
68 2.0f/16.0f, 2.0f/16.0f};
70 const float BLUR_KERNEL1[] = {8.0f/16.0f,
71 4.0f/16.0f, 4.0f/16.0f };
73 const float BLUR_KERNEL2[] = {6.0f/16.0f,
74 2.5f/16.0f, 2.5f/16.0f,
75 1.5f/16.0f, 1.5f/16.0f,
76 1.0f/16.0f, 1.0f/16.0f};
78 const float BLUR_KERNEL3[] = {4.0f/16.0f,
79 3.0f/16.0f, 2.0f/16.0f,
80 2.0f/16.0f, 2.0f/16.0f,
81 1.0f/16.0f, 1.0f/16.0f};
83 const float BLUR_KERNEL4[] = {3.0f/16.0f,
84 2.5f/16.0f, 2.5f/16.0f,
85 1.75f/16.0f, 1.75f/16.0f,
86 1.25f/16.0f, 1.25f/16.0f,
87 1.0f/16.0f, 1.0f/16.0f};
91 Toolkit::EffectsView EffectsView::New()
93 EffectsView* effectsView = new EffectsView;
95 Toolkit::EffectsView handle = Toolkit::EffectsView(*effectsView);
97 // Second-phase init of the implementation
98 // This can only be done after the CustomActor connection has been made...
99 effectsView->Initialize();
104 EffectsView::EffectsView()
105 : Control(ControlBehaviour(CONTROL_BEHAVIOUR_DEFAULT)),
106 mChildrenRoot(Actor::New()),
107 mBackgroundColor(EFFECTS_VIEW_DEFAULT_BACKGROUND_COLOR),
108 mTargetSize(Vector2::ZERO),
109 mLastSize(Vector2::ZERO),
111 mEffectType(Toolkit::EffectsView::INVALID_TYPE),
112 mPixelFormat(EFFECTS_VIEW_DEFAULT_PIXEL_FORMAT),
114 mRefreshOnDemand(EFFECTS_VIEW_REFRESH_ON_DEMAND)
118 EffectsView::~EffectsView()
123 void EffectsView::SetType(Toolkit::EffectsView::EffectType type)
125 if(mEffectType != type)
133 case Toolkit::EffectsView::DROP_SHADOW:
135 mFilters.PushBack(new SpreadFilter);
136 mFilters.PushBack(new BlurTwoPassFilter);
139 case Toolkit::EffectsView::EMBOSS:
141 mFilters.PushBack(new SpreadFilter);
142 mFilters.PushBack(new EmbossFilter);
143 mFilters.PushBack(new BlurTwoPassFilter);
156 Toolkit::EffectsView::EffectType EffectsView::GetType() const
161 void EffectsView::Enable()
163 // make sure resources are allocated and start the render tasks processing
169 void EffectsView::Disable()
171 // stop render tasks processing
173 mLastSize = Vector2::ZERO; // Ensure resources are reallocated on subsequent enable
177 void EffectsView::Refresh()
179 RefreshRenderTasks();
182 void EffectsView::SetRefreshOnDemand(bool onDemand)
184 mRefreshOnDemand = onDemand;
186 RefreshRenderTasks();
189 void EffectsView::SetPixelFormat(Pixel::Format pixelFormat)
191 mPixelFormat = pixelFormat;
194 void EffectsView::SetBackgroundColor(const Vector4& color)
196 mBackgroundColor = color;
199 Vector4 EffectsView::GetBackgroundColor() const
201 return mBackgroundColor;
204 void EffectsView::SetEffectSize(int effectSize)
206 mEffectSize = effectSize;
210 const size_t numFilters(mFilters.Size());
211 for(size_t i = 0; i < numFilters; ++i)
213 mFilters[i]->Disable();
218 for(size_t i = 0; i < numFilters; ++i)
220 mFilters[i]->Enable();
225 int EffectsView::GetEffectSize()
231 void EffectsView::OnInitialize()
233 CustomActor self = Self();
234 mChildrenRoot.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
235 self.Add(mChildrenRoot);
237 DevelControl::SetAccessibilityConstructor(self, [](Dali::Actor actor) {
238 return std::unique_ptr<Dali::Accessibility::Accessible>(
239 new DevelControl::AccessibleImpl(actor, Dali::Accessibility::Role::FILLER));
243 void EffectsView::OnSizeSet(const Vector3& targetSize)
245 mTargetSize = Vector2(targetSize);
247 // if we are already on stage, need to update render target sizes now to reflect the new size of this actor
250 if(mLastSize != Vector2::ZERO)
257 mChildrenRoot.SetProperty(Actor::Property::SIZE, targetSize);
259 Control::OnSizeSet(targetSize);
262 void EffectsView::OnSceneConnection(int depth)
267 mRendererPostFilter = CreateRenderer(SHADER_EFFECTS_VIEW_VERT,
268 SHADER_EFFECTS_VIEW_FRAG);
269 mRendererPostFilter.SetProperty(Dali::Renderer::Property::DEPTH_INDEX, DepthIndex::CONTENT);
270 self.AddRenderer(mRendererPostFilter);
272 mRendererForChildren = CreateRenderer(BASIC_VERTEX_SOURCE, BASIC_FRAGMENT_SOURCE);
273 mRendererForChildren.SetProperty(Dali::Renderer::Property::DEPTH_INDEX, DepthIndex::CONTENT + 1);
274 self.AddRenderer(mRendererForChildren);
278 Control::OnSceneConnection(depth);
281 void EffectsView::OnSceneDisconnection()
287 const size_t numFilters(mFilters.Size());
288 for(size_t i = 0; i < numFilters; ++i)
290 mFilters[i]->Disable();
294 self.RemoveRenderer(mRendererForChildren);
295 mRendererForChildren.Reset();
297 self.RemoveRenderer(mRendererPostFilter);
298 mRendererPostFilter.Reset();
300 Control::OnSceneDisconnection();
303 void EffectsView::OnChildAdd(Actor& child)
305 if(child != mChildrenRoot && child != mCameraForChildren)
307 mChildrenRoot.Add(child);
310 Control::OnChildAdd(child);
313 void EffectsView::OnChildRemove(Actor& child)
315 mChildrenRoot.Remove(child);
317 Control::OnChildRemove(child);
320 void EffectsView::SetupFilters()
324 case Toolkit::EffectsView::DROP_SHADOW:
326 SpreadFilter* spreadFilter = static_cast<SpreadFilter*>(mFilters[0]);
327 spreadFilter->SetInputTexture(mFrameBufferForChildren.GetColorTexture());
328 spreadFilter->SetOutputFrameBuffer(mFrameBufferPostFilter);
329 spreadFilter->SetRootActor(mChildrenRoot);
330 spreadFilter->SetBackgroundColor(mBackgroundColor);
331 spreadFilter->SetPixelFormat(mPixelFormat);
332 spreadFilter->SetSize(mTargetSize);
333 spreadFilter->SetSpread(mEffectSize);
335 BlurTwoPassFilter* blurFilter = static_cast<BlurTwoPassFilter*>(mFilters[1]);
336 blurFilter->SetInputTexture(mFrameBufferPostFilter.GetColorTexture());
337 blurFilter->SetOutputFrameBuffer(mFrameBufferPostFilter);
338 blurFilter->SetRootActor(mChildrenRoot);
339 blurFilter->SetBackgroundColor(mBackgroundColor);
340 blurFilter->SetPixelFormat(mPixelFormat);
341 blurFilter->SetSize(mTargetSize);
343 const float* kernel(NULL);
344 size_t kernelSize(0);
349 kernel = BLUR_KERNEL4;
350 kernelSize = sizeof(BLUR_KERNEL4) / sizeof(BLUR_KERNEL4[0]);
355 kernel = BLUR_KERNEL3;
356 kernelSize = sizeof(BLUR_KERNEL3) / sizeof(BLUR_KERNEL3[0]);
361 kernel = BLUR_KERNEL2;
362 kernelSize = sizeof(BLUR_KERNEL2) / sizeof(BLUR_KERNEL2[0]);
367 kernel = BLUR_KERNEL1;
368 kernelSize = sizeof(BLUR_KERNEL1) / sizeof(BLUR_KERNEL1[0]);
374 kernel = BLUR_KERNEL0;
375 kernelSize = sizeof(BLUR_KERNEL0) / sizeof(BLUR_KERNEL0[0]);
379 blurFilter->CreateKernel(kernel, kernelSize);
382 case Toolkit::EffectsView::EMBOSS:
384 SpreadFilter* spreadFilter = static_cast<SpreadFilter*>(mFilters[0]);
385 spreadFilter->SetInputTexture(mFrameBufferForChildren.GetColorTexture());
386 spreadFilter->SetOutputFrameBuffer(mFrameBufferPostFilter);
387 spreadFilter->SetRootActor(mChildrenRoot);
388 spreadFilter->SetBackgroundColor(mBackgroundColor);
389 spreadFilter->SetPixelFormat(Pixel::RGBA8888);
390 spreadFilter->SetSize(mTargetSize);
391 spreadFilter->SetSpread(mEffectSize);
393 EmbossFilter* embossFilter = static_cast<EmbossFilter*>(mFilters[1]);
394 embossFilter->SetInputTexture(mFrameBufferPostFilter.GetColorTexture());
395 embossFilter->SetOutputFrameBuffer(mFrameBufferPostFilter);
396 embossFilter->SetRootActor(mChildrenRoot);
397 embossFilter->SetBackgroundColor(mBackgroundColor);
398 embossFilter->SetPixelFormat(Pixel::RGBA8888);
399 embossFilter->SetSize(mTargetSize);
401 BlurTwoPassFilter* blurFilter = static_cast<BlurTwoPassFilter*>(mFilters[2]);
402 blurFilter->SetInputTexture(mFrameBufferPostFilter.GetColorTexture());
403 blurFilter->SetOutputFrameBuffer(mFrameBufferPostFilter);
404 blurFilter->SetRootActor(mChildrenRoot);
405 blurFilter->SetBackgroundColor(Vector4(0.5f, 0.5f, 0.5f, 0.0));
406 blurFilter->SetPixelFormat(Pixel::RGBA8888);
407 blurFilter->SetSize(mTargetSize);
408 blurFilter->CreateKernel(BLUR_KERNEL0, sizeof(BLUR_KERNEL0) / sizeof(BLUR_KERNEL0[0]));
419 void EffectsView::AllocateResources()
421 if(mTargetSize != mLastSize)
423 mLastSize = mTargetSize;
428 mFrameBufferForChildren = FrameBuffer::New(mTargetSize.width, mTargetSize.height, FrameBuffer::Attachment::NONE);
429 Texture textureForChildren = Texture::New(TextureType::TEXTURE_2D, mPixelFormat, unsigned(mTargetSize.width), unsigned(mTargetSize.height));
430 mFrameBufferForChildren.AttachColorTexture(textureForChildren);
432 SetRendererTexture(mRendererForChildren, textureForChildren);
434 mFrameBufferPostFilter = FrameBuffer::New(mTargetSize.width, mTargetSize.height, FrameBuffer::Attachment::NONE);
435 Texture texturePostFilter = Texture::New(TextureType::TEXTURE_2D, mPixelFormat, unsigned(mTargetSize.width), unsigned(mTargetSize.height));
436 mFrameBufferPostFilter.AttachColorTexture(texturePostFilter);
438 SetRendererTexture(mRendererPostFilter, texturePostFilter);
444 void EffectsView::SetupCameras()
446 if(!mCameraForChildren)
448 // Create a camera for the children render, corresponding to its render target size
449 mCameraForChildren = CameraActor::New(mTargetSize);
450 mCameraForChildren.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
451 mCameraForChildren.SetInvertYAxis(true);
452 Self().Add(mCameraForChildren);
456 // place the camera for the children render, corresponding to its render target size
457 const float cameraPosScale(0.5f / tanf(ARBITRARY_FIELD_OF_VIEW * 0.5f));
458 mCameraForChildren.SetFieldOfView(ARBITRARY_FIELD_OF_VIEW);
459 mCameraForChildren.SetNearClippingPlane(1.0f);
460 mCameraForChildren.SetAspectRatio(mTargetSize.width / mTargetSize.height);
461 mCameraForChildren.SetType(Dali::Camera::FREE_LOOK); // camera orientation based solely on actor
462 mCameraForChildren.SetProperty(Actor::Property::POSITION, Vector3(0.0f, 0.0f, mTargetSize.height * cameraPosScale));
463 mCameraForChildren.SetProperty(Actor::Property::POSITION_Z, mTargetSize.height * cameraPosScale);
467 void EffectsView::CreateRenderTasks()
469 if(mTargetSize == Vector2::ZERO)
473 RenderTaskList taskList = Stage::GetCurrent().GetRenderTaskList();
475 // create render task to render our child actors to offscreen buffer
476 mRenderTaskForChildren = taskList.CreateTask();
477 mRenderTaskForChildren.SetRefreshRate(mRefreshOnDemand ? RenderTask::REFRESH_ONCE : RenderTask::REFRESH_ALWAYS);
478 mRenderTaskForChildren.SetSourceActor(mChildrenRoot);
479 mRenderTaskForChildren.SetExclusive(true);
480 mRenderTaskForChildren.SetInputEnabled(false);
481 mRenderTaskForChildren.SetClearColor(mBackgroundColor);
482 mRenderTaskForChildren.SetClearEnabled(true);
483 mRenderTaskForChildren.SetFrameBuffer(mFrameBufferForChildren);
484 mRenderTaskForChildren.SetCameraActor(mCameraForChildren); // use camera that covers render target exactly
486 // Enable image filters
487 const size_t numFilters(mFilters.Size());
488 for(size_t i = 0; i < numFilters; ++i)
490 mFilters[i]->Enable();
494 void EffectsView::RemoveRenderTasks()
496 if(mTargetSize == Vector2::ZERO)
501 RenderTaskList taskList = Stage::GetCurrent().GetRenderTaskList();
503 taskList.RemoveTask(mRenderTaskForChildren);
505 const size_t numFilters(mFilters.Size());
506 for(size_t i = 0; i < numFilters; ++i)
508 mFilters[i]->Disable();
512 void EffectsView::RefreshRenderTasks()
514 RenderTaskList taskList = Stage::GetCurrent().GetRenderTaskList();
516 if(mRenderTaskForChildren)
518 mRenderTaskForChildren.SetRefreshRate(mRefreshOnDemand ? RenderTask::REFRESH_ONCE : RenderTask::REFRESH_ALWAYS);
521 const size_t numFilters(mFilters.Size());
522 for(size_t i = 0; i < numFilters; ++i)
524 mFilters[i]->Refresh();
528 void EffectsView::RemoveFilters()
530 const size_t numFilters(mFilters.Size());
531 for(size_t i = 0; i < numFilters; ++i)
538 void EffectsView::SetProperty(BaseObject* object, Property::Index index, const Property::Value& value)
540 Toolkit::EffectsView effectsView = Toolkit::EffectsView::DownCast(Dali::BaseHandle(object));
546 case Toolkit::EffectsView::Property::EFFECT_SIZE:
549 if(value.Get(effectSize))
551 GetImpl(effectsView).SetEffectSize(effectSize);
563 Property::Value EffectsView::GetProperty(BaseObject* object, Property::Index propertyIndex)
565 Property::Value value;
567 Toolkit::EffectsView imageview = Toolkit::EffectsView::DownCast(Dali::BaseHandle(object));
571 EffectsView& impl = GetImpl(imageview);
572 switch(propertyIndex)
574 case Toolkit::EffectsView::Property::EFFECT_SIZE:
576 value = impl.GetEffectSize();
589 } // namespace Internal
591 } // namespace Toolkit