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::make_unique<DevelControl::ControlAccessible>(actor, Dali::Accessibility::Role::FILLER);
242 void EffectsView::OnSizeSet(const Vector3& targetSize)
244 mTargetSize = Vector2(targetSize);
246 // if we are already on stage, need to update render target sizes now to reflect the new size of this actor
249 if(mLastSize != Vector2::ZERO)
256 mChildrenRoot.SetProperty(Actor::Property::SIZE, targetSize);
258 Control::OnSizeSet(targetSize);
261 void EffectsView::OnSceneConnection(int depth)
266 mRendererPostFilter = CreateRenderer(SHADER_EFFECTS_VIEW_VERT,
267 SHADER_EFFECTS_VIEW_FRAG);
268 mRendererPostFilter.SetProperty(Dali::Renderer::Property::DEPTH_INDEX, DepthIndex::CONTENT);
269 self.AddRenderer(mRendererPostFilter);
271 mRendererForChildren = CreateRenderer(BASIC_VERTEX_SOURCE, BASIC_FRAGMENT_SOURCE);
272 mRendererForChildren.SetProperty(Dali::Renderer::Property::DEPTH_INDEX, DepthIndex::CONTENT + 1);
273 self.AddRenderer(mRendererForChildren);
277 Control::OnSceneConnection(depth);
280 void EffectsView::OnSceneDisconnection()
286 const size_t numFilters(mFilters.Size());
287 for(size_t i = 0; i < numFilters; ++i)
289 mFilters[i]->Disable();
293 self.RemoveRenderer(mRendererForChildren);
294 mRendererForChildren.Reset();
296 self.RemoveRenderer(mRendererPostFilter);
297 mRendererPostFilter.Reset();
299 Control::OnSceneDisconnection();
302 void EffectsView::OnChildAdd(Actor& child)
304 if(child != mChildrenRoot && child != mCameraForChildren)
306 mChildrenRoot.Add(child);
309 Control::OnChildAdd(child);
312 void EffectsView::OnChildRemove(Actor& child)
314 mChildrenRoot.Remove(child);
316 Control::OnChildRemove(child);
319 void EffectsView::SetupFilters()
323 case Toolkit::EffectsView::DROP_SHADOW:
325 SpreadFilter* spreadFilter = static_cast<SpreadFilter*>(mFilters[0]);
326 spreadFilter->SetInputTexture(mFrameBufferForChildren.GetColorTexture());
327 spreadFilter->SetOutputFrameBuffer(mFrameBufferPostFilter);
328 spreadFilter->SetRootActor(mChildrenRoot);
329 spreadFilter->SetBackgroundColor(mBackgroundColor);
330 spreadFilter->SetPixelFormat(mPixelFormat);
331 spreadFilter->SetSize(mTargetSize);
332 spreadFilter->SetSpread(mEffectSize);
334 BlurTwoPassFilter* blurFilter = static_cast<BlurTwoPassFilter*>(mFilters[1]);
335 blurFilter->SetInputTexture(mFrameBufferPostFilter.GetColorTexture());
336 blurFilter->SetOutputFrameBuffer(mFrameBufferPostFilter);
337 blurFilter->SetRootActor(mChildrenRoot);
338 blurFilter->SetBackgroundColor(mBackgroundColor);
339 blurFilter->SetPixelFormat(mPixelFormat);
340 blurFilter->SetSize(mTargetSize);
342 const float* kernel(NULL);
343 size_t kernelSize(0);
348 kernel = BLUR_KERNEL4;
349 kernelSize = sizeof(BLUR_KERNEL4) / sizeof(BLUR_KERNEL4[0]);
354 kernel = BLUR_KERNEL3;
355 kernelSize = sizeof(BLUR_KERNEL3) / sizeof(BLUR_KERNEL3[0]);
360 kernel = BLUR_KERNEL2;
361 kernelSize = sizeof(BLUR_KERNEL2) / sizeof(BLUR_KERNEL2[0]);
366 kernel = BLUR_KERNEL1;
367 kernelSize = sizeof(BLUR_KERNEL1) / sizeof(BLUR_KERNEL1[0]);
373 kernel = BLUR_KERNEL0;
374 kernelSize = sizeof(BLUR_KERNEL0) / sizeof(BLUR_KERNEL0[0]);
378 blurFilter->CreateKernel(kernel, kernelSize);
381 case Toolkit::EffectsView::EMBOSS:
383 SpreadFilter* spreadFilter = static_cast<SpreadFilter*>(mFilters[0]);
384 spreadFilter->SetInputTexture(mFrameBufferForChildren.GetColorTexture());
385 spreadFilter->SetOutputFrameBuffer(mFrameBufferPostFilter);
386 spreadFilter->SetRootActor(mChildrenRoot);
387 spreadFilter->SetBackgroundColor(mBackgroundColor);
388 spreadFilter->SetPixelFormat(Pixel::RGBA8888);
389 spreadFilter->SetSize(mTargetSize);
390 spreadFilter->SetSpread(mEffectSize);
392 EmbossFilter* embossFilter = static_cast<EmbossFilter*>(mFilters[1]);
393 embossFilter->SetInputTexture(mFrameBufferPostFilter.GetColorTexture());
394 embossFilter->SetOutputFrameBuffer(mFrameBufferPostFilter);
395 embossFilter->SetRootActor(mChildrenRoot);
396 embossFilter->SetBackgroundColor(mBackgroundColor);
397 embossFilter->SetPixelFormat(Pixel::RGBA8888);
398 embossFilter->SetSize(mTargetSize);
400 BlurTwoPassFilter* blurFilter = static_cast<BlurTwoPassFilter*>(mFilters[2]);
401 blurFilter->SetInputTexture(mFrameBufferPostFilter.GetColorTexture());
402 blurFilter->SetOutputFrameBuffer(mFrameBufferPostFilter);
403 blurFilter->SetRootActor(mChildrenRoot);
404 blurFilter->SetBackgroundColor(Vector4(0.5f, 0.5f, 0.5f, 0.0));
405 blurFilter->SetPixelFormat(Pixel::RGBA8888);
406 blurFilter->SetSize(mTargetSize);
407 blurFilter->CreateKernel(BLUR_KERNEL0, sizeof(BLUR_KERNEL0) / sizeof(BLUR_KERNEL0[0]));
418 void EffectsView::AllocateResources()
420 if(mTargetSize != mLastSize)
422 mLastSize = mTargetSize;
427 mFrameBufferForChildren = FrameBuffer::New(mTargetSize.width, mTargetSize.height, FrameBuffer::Attachment::NONE);
428 Texture textureForChildren = Texture::New(TextureType::TEXTURE_2D, mPixelFormat, unsigned(mTargetSize.width), unsigned(mTargetSize.height));
429 mFrameBufferForChildren.AttachColorTexture(textureForChildren);
431 SetRendererTexture(mRendererForChildren, textureForChildren);
433 mFrameBufferPostFilter = FrameBuffer::New(mTargetSize.width, mTargetSize.height, FrameBuffer::Attachment::NONE);
434 Texture texturePostFilter = Texture::New(TextureType::TEXTURE_2D, mPixelFormat, unsigned(mTargetSize.width), unsigned(mTargetSize.height));
435 mFrameBufferPostFilter.AttachColorTexture(texturePostFilter);
437 SetRendererTexture(mRendererPostFilter, texturePostFilter);
443 void EffectsView::SetupCameras()
445 if(!mCameraForChildren)
447 // Create a camera for the children render, corresponding to its render target size
448 mCameraForChildren = CameraActor::New(mTargetSize);
449 mCameraForChildren.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
450 mCameraForChildren.SetInvertYAxis(true);
451 Self().Add(mCameraForChildren);
455 // place the camera for the children render, corresponding to its render target size
456 const float cameraPosScale(0.5f / tanf(ARBITRARY_FIELD_OF_VIEW * 0.5f));
457 mCameraForChildren.SetFieldOfView(ARBITRARY_FIELD_OF_VIEW);
458 mCameraForChildren.SetNearClippingPlane(1.0f);
459 mCameraForChildren.SetAspectRatio(mTargetSize.width / mTargetSize.height);
460 mCameraForChildren.SetType(Dali::Camera::FREE_LOOK); // camera orientation based solely on actor
461 mCameraForChildren.SetProperty(Actor::Property::POSITION, Vector3(0.0f, 0.0f, mTargetSize.height * cameraPosScale));
462 mCameraForChildren.SetProperty(Actor::Property::POSITION_Z, mTargetSize.height * cameraPosScale);
466 void EffectsView::CreateRenderTasks()
468 if(mTargetSize == Vector2::ZERO)
472 RenderTaskList taskList = Stage::GetCurrent().GetRenderTaskList();
474 // create render task to render our child actors to offscreen buffer
475 mRenderTaskForChildren = taskList.CreateTask();
476 mRenderTaskForChildren.SetRefreshRate(mRefreshOnDemand ? RenderTask::REFRESH_ONCE : RenderTask::REFRESH_ALWAYS);
477 mRenderTaskForChildren.SetSourceActor(mChildrenRoot);
478 mRenderTaskForChildren.SetExclusive(true);
479 mRenderTaskForChildren.SetInputEnabled(false);
480 mRenderTaskForChildren.SetClearColor(mBackgroundColor);
481 mRenderTaskForChildren.SetClearEnabled(true);
482 mRenderTaskForChildren.SetFrameBuffer(mFrameBufferForChildren);
483 mRenderTaskForChildren.SetCameraActor(mCameraForChildren); // use camera that covers render target exactly
485 // Enable image filters
486 const size_t numFilters(mFilters.Size());
487 for(size_t i = 0; i < numFilters; ++i)
489 mFilters[i]->Enable();
493 void EffectsView::RemoveRenderTasks()
495 if(mTargetSize == Vector2::ZERO)
500 RenderTaskList taskList = Stage::GetCurrent().GetRenderTaskList();
502 taskList.RemoveTask(mRenderTaskForChildren);
504 const size_t numFilters(mFilters.Size());
505 for(size_t i = 0; i < numFilters; ++i)
507 mFilters[i]->Disable();
511 void EffectsView::RefreshRenderTasks()
513 RenderTaskList taskList = Stage::GetCurrent().GetRenderTaskList();
515 if(mRenderTaskForChildren)
517 mRenderTaskForChildren.SetRefreshRate(mRefreshOnDemand ? RenderTask::REFRESH_ONCE : RenderTask::REFRESH_ALWAYS);
520 const size_t numFilters(mFilters.Size());
521 for(size_t i = 0; i < numFilters; ++i)
523 mFilters[i]->Refresh();
527 void EffectsView::RemoveFilters()
529 const size_t numFilters(mFilters.Size());
530 for(size_t i = 0; i < numFilters; ++i)
537 void EffectsView::SetProperty(BaseObject* object, Property::Index index, const Property::Value& value)
539 Toolkit::EffectsView effectsView = Toolkit::EffectsView::DownCast(Dali::BaseHandle(object));
545 case Toolkit::EffectsView::Property::EFFECT_SIZE:
548 if(value.Get(effectSize))
550 GetImpl(effectsView).SetEffectSize(effectSize);
562 Property::Value EffectsView::GetProperty(BaseObject* object, Property::Index propertyIndex)
564 Property::Value value;
566 Toolkit::EffectsView imageview = Toolkit::EffectsView::DownCast(Dali::BaseHandle(object));
570 EffectsView& impl = GetImpl(imageview);
571 switch(propertyIndex)
573 case Toolkit::EffectsView::Property::EFFECT_SIZE:
575 value = impl.GetEffectSize();
588 } // namespace Internal
590 } // namespace Toolkit