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 self.SetProperty(DevelControl::Property::ACCESSIBILITY_ROLE, Dali::Accessibility::Role::FILLER);
240 void EffectsView::OnSizeSet(const Vector3& targetSize)
242 mTargetSize = Vector2(targetSize);
244 // if we are already on stage, need to update render target sizes now to reflect the new size of this actor
247 if(mLastSize != Vector2::ZERO)
254 mChildrenRoot.SetProperty(Actor::Property::SIZE, targetSize);
256 Control::OnSizeSet(targetSize);
259 void EffectsView::OnSceneConnection(int depth)
264 mRendererPostFilter = CreateRenderer(SHADER_EFFECTS_VIEW_VERT,
265 SHADER_EFFECTS_VIEW_FRAG);
266 mRendererPostFilter.SetProperty(Dali::Renderer::Property::DEPTH_INDEX, DepthIndex::CONTENT);
267 self.AddRenderer(mRendererPostFilter);
269 mRendererForChildren = CreateRenderer(BASIC_VERTEX_SOURCE, BASIC_FRAGMENT_SOURCE);
270 mRendererForChildren.SetProperty(Dali::Renderer::Property::DEPTH_INDEX, DepthIndex::CONTENT + 1);
271 self.AddRenderer(mRendererForChildren);
275 Control::OnSceneConnection(depth);
278 void EffectsView::OnSceneDisconnection()
284 const size_t numFilters(mFilters.Size());
285 for(size_t i = 0; i < numFilters; ++i)
287 mFilters[i]->Disable();
291 self.RemoveRenderer(mRendererForChildren);
292 mRendererForChildren.Reset();
294 self.RemoveRenderer(mRendererPostFilter);
295 mRendererPostFilter.Reset();
297 Control::OnSceneDisconnection();
300 void EffectsView::OnChildAdd(Actor& child)
302 if(child != mChildrenRoot && child != mCameraForChildren)
304 mChildrenRoot.Add(child);
307 Control::OnChildAdd(child);
310 void EffectsView::OnChildRemove(Actor& child)
312 mChildrenRoot.Remove(child);
314 Control::OnChildRemove(child);
317 void EffectsView::SetupFilters()
321 case Toolkit::EffectsView::DROP_SHADOW:
323 SpreadFilter* spreadFilter = static_cast<SpreadFilter*>(mFilters[0]);
324 spreadFilter->SetInputTexture(mFrameBufferForChildren.GetColorTexture());
325 spreadFilter->SetOutputFrameBuffer(mFrameBufferPostFilter);
326 spreadFilter->SetRootActor(mChildrenRoot);
327 spreadFilter->SetBackgroundColor(mBackgroundColor);
328 spreadFilter->SetPixelFormat(mPixelFormat);
329 spreadFilter->SetSize(mTargetSize);
330 spreadFilter->SetSpread(mEffectSize);
332 BlurTwoPassFilter* blurFilter = static_cast<BlurTwoPassFilter*>(mFilters[1]);
333 blurFilter->SetInputTexture(mFrameBufferPostFilter.GetColorTexture());
334 blurFilter->SetOutputFrameBuffer(mFrameBufferPostFilter);
335 blurFilter->SetRootActor(mChildrenRoot);
336 blurFilter->SetBackgroundColor(mBackgroundColor);
337 blurFilter->SetPixelFormat(mPixelFormat);
338 blurFilter->SetSize(mTargetSize);
340 const float* kernel(NULL);
341 size_t kernelSize(0);
346 kernel = BLUR_KERNEL4;
347 kernelSize = sizeof(BLUR_KERNEL4) / sizeof(BLUR_KERNEL4[0]);
352 kernel = BLUR_KERNEL3;
353 kernelSize = sizeof(BLUR_KERNEL3) / sizeof(BLUR_KERNEL3[0]);
358 kernel = BLUR_KERNEL2;
359 kernelSize = sizeof(BLUR_KERNEL2) / sizeof(BLUR_KERNEL2[0]);
364 kernel = BLUR_KERNEL1;
365 kernelSize = sizeof(BLUR_KERNEL1) / sizeof(BLUR_KERNEL1[0]);
371 kernel = BLUR_KERNEL0;
372 kernelSize = sizeof(BLUR_KERNEL0) / sizeof(BLUR_KERNEL0[0]);
376 blurFilter->CreateKernel(kernel, kernelSize);
379 case Toolkit::EffectsView::EMBOSS:
381 SpreadFilter* spreadFilter = static_cast<SpreadFilter*>(mFilters[0]);
382 spreadFilter->SetInputTexture(mFrameBufferForChildren.GetColorTexture());
383 spreadFilter->SetOutputFrameBuffer(mFrameBufferPostFilter);
384 spreadFilter->SetRootActor(mChildrenRoot);
385 spreadFilter->SetBackgroundColor(mBackgroundColor);
386 spreadFilter->SetPixelFormat(Pixel::RGBA8888);
387 spreadFilter->SetSize(mTargetSize);
388 spreadFilter->SetSpread(mEffectSize);
390 EmbossFilter* embossFilter = static_cast<EmbossFilter*>(mFilters[1]);
391 embossFilter->SetInputTexture(mFrameBufferPostFilter.GetColorTexture());
392 embossFilter->SetOutputFrameBuffer(mFrameBufferPostFilter);
393 embossFilter->SetRootActor(mChildrenRoot);
394 embossFilter->SetBackgroundColor(mBackgroundColor);
395 embossFilter->SetPixelFormat(Pixel::RGBA8888);
396 embossFilter->SetSize(mTargetSize);
398 BlurTwoPassFilter* blurFilter = static_cast<BlurTwoPassFilter*>(mFilters[2]);
399 blurFilter->SetInputTexture(mFrameBufferPostFilter.GetColorTexture());
400 blurFilter->SetOutputFrameBuffer(mFrameBufferPostFilter);
401 blurFilter->SetRootActor(mChildrenRoot);
402 blurFilter->SetBackgroundColor(Vector4(0.5f, 0.5f, 0.5f, 0.0));
403 blurFilter->SetPixelFormat(Pixel::RGBA8888);
404 blurFilter->SetSize(mTargetSize);
405 blurFilter->CreateKernel(BLUR_KERNEL0, sizeof(BLUR_KERNEL0) / sizeof(BLUR_KERNEL0[0]));
416 void EffectsView::AllocateResources()
418 if(mTargetSize != mLastSize)
420 mLastSize = mTargetSize;
425 mFrameBufferForChildren = FrameBuffer::New(mTargetSize.width, mTargetSize.height, FrameBuffer::Attachment::NONE);
426 Texture textureForChildren = Texture::New(TextureType::TEXTURE_2D, mPixelFormat, unsigned(mTargetSize.width), unsigned(mTargetSize.height));
427 mFrameBufferForChildren.AttachColorTexture(textureForChildren);
429 SetRendererTexture(mRendererForChildren, textureForChildren);
431 mFrameBufferPostFilter = FrameBuffer::New(mTargetSize.width, mTargetSize.height, FrameBuffer::Attachment::NONE);
432 Texture texturePostFilter = Texture::New(TextureType::TEXTURE_2D, mPixelFormat, unsigned(mTargetSize.width), unsigned(mTargetSize.height));
433 mFrameBufferPostFilter.AttachColorTexture(texturePostFilter);
435 SetRendererTexture(mRendererPostFilter, texturePostFilter);
441 void EffectsView::SetupCameras()
443 if(!mCameraForChildren)
445 // Create a camera for the children render, corresponding to its render target size
446 mCameraForChildren = CameraActor::New(mTargetSize);
447 mCameraForChildren.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
448 mCameraForChildren.SetInvertYAxis(true);
449 Self().Add(mCameraForChildren);
453 // place the camera for the children render, corresponding to its render target size
454 const float cameraPosScale(0.5f / tanf(ARBITRARY_FIELD_OF_VIEW * 0.5f));
455 mCameraForChildren.SetFieldOfView(ARBITRARY_FIELD_OF_VIEW);
456 mCameraForChildren.SetNearClippingPlane(1.0f);
457 mCameraForChildren.SetAspectRatio(mTargetSize.width / mTargetSize.height);
458 mCameraForChildren.SetType(Dali::Camera::FREE_LOOK); // camera orientation based solely on actor
459 mCameraForChildren.SetProperty(Actor::Property::POSITION, Vector3(0.0f, 0.0f, mTargetSize.height * cameraPosScale));
460 mCameraForChildren.SetProperty(Actor::Property::POSITION_Z, mTargetSize.height * cameraPosScale);
464 void EffectsView::CreateRenderTasks()
466 if(mTargetSize == Vector2::ZERO)
470 RenderTaskList taskList = Stage::GetCurrent().GetRenderTaskList();
472 // create render task to render our child actors to offscreen buffer
473 mRenderTaskForChildren = taskList.CreateTask();
474 mRenderTaskForChildren.SetRefreshRate(mRefreshOnDemand ? RenderTask::REFRESH_ONCE : RenderTask::REFRESH_ALWAYS);
475 mRenderTaskForChildren.SetSourceActor(mChildrenRoot);
476 mRenderTaskForChildren.SetExclusive(true);
477 mRenderTaskForChildren.SetInputEnabled(false);
478 mRenderTaskForChildren.SetClearColor(mBackgroundColor);
479 mRenderTaskForChildren.SetClearEnabled(true);
480 mRenderTaskForChildren.SetFrameBuffer(mFrameBufferForChildren);
481 mRenderTaskForChildren.SetCameraActor(mCameraForChildren); // use camera that covers render target exactly
483 // Enable image filters
484 const size_t numFilters(mFilters.Size());
485 for(size_t i = 0; i < numFilters; ++i)
487 mFilters[i]->Enable();
491 void EffectsView::RemoveRenderTasks()
493 if(mTargetSize == Vector2::ZERO)
498 RenderTaskList taskList = Stage::GetCurrent().GetRenderTaskList();
500 taskList.RemoveTask(mRenderTaskForChildren);
502 const size_t numFilters(mFilters.Size());
503 for(size_t i = 0; i < numFilters; ++i)
505 mFilters[i]->Disable();
509 void EffectsView::RefreshRenderTasks()
511 RenderTaskList taskList = Stage::GetCurrent().GetRenderTaskList();
513 if(mRenderTaskForChildren)
515 mRenderTaskForChildren.SetRefreshRate(mRefreshOnDemand ? RenderTask::REFRESH_ONCE : RenderTask::REFRESH_ALWAYS);
518 const size_t numFilters(mFilters.Size());
519 for(size_t i = 0; i < numFilters; ++i)
521 mFilters[i]->Refresh();
525 void EffectsView::RemoveFilters()
527 const size_t numFilters(mFilters.Size());
528 for(size_t i = 0; i < numFilters; ++i)
535 void EffectsView::SetProperty(BaseObject* object, Property::Index index, const Property::Value& value)
537 Toolkit::EffectsView effectsView = Toolkit::EffectsView::DownCast(Dali::BaseHandle(object));
543 case Toolkit::EffectsView::Property::EFFECT_SIZE:
546 if(value.Get(effectSize))
548 GetImpl(effectsView).SetEffectSize(effectSize);
560 Property::Value EffectsView::GetProperty(BaseObject* object, Property::Index propertyIndex)
562 Property::Value value;
564 Toolkit::EffectsView imageview = Toolkit::EffectsView::DownCast(Dali::BaseHandle(object));
568 EffectsView& impl = GetImpl(imageview);
569 switch(propertyIndex)
571 case Toolkit::EffectsView::Property::EFFECT_SIZE:
573 value = impl.GetEffectSize();
586 } // namespace Internal
588 } // namespace Toolkit