2 * Copyright (c) 2020 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/public-api/animation/constraint.h>
23 #include <dali/public-api/animation/constraints.h>
24 #include <dali/devel-api/common/stage.h>
25 #include <dali/public-api/object/property.h>
26 #include <dali/public-api/object/property-map.h>
27 #include <dali/public-api/object/type-registry.h>
28 #include <dali/public-api/object/type-registry-helper.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/filters/blur-two-pass-filter.h>
36 #include <dali-toolkit/internal/filters/emboss-filter.h>
37 #include <dali-toolkit/internal/filters/spread-filter.h>
38 #include <dali-toolkit/internal/controls/control/control-renderers.h>
39 #include <dali-toolkit/internal/controls/control/control-data-impl.h>
53 Dali::BaseHandle Create()
55 return EffectsView::New();
58 DALI_TYPE_REGISTRATION_BEGIN( Toolkit::EffectsView, Toolkit::Control, Create )
59 DALI_PROPERTY_REGISTRATION( Toolkit, EffectsView, "effectSize", INTEGER, EFFECT_SIZE )
60 DALI_ANIMATABLE_PROPERTY_REGISTRATION( Toolkit, EffectsView, "effectOffset", VECTOR3, EFFECT_OFFSET )
61 DALI_ANIMATABLE_PROPERTY_REGISTRATION_WITH_DEFAULT( Toolkit, EffectsView, "effectColor", Color::WHITE, EFFECT_COLOR )
62 DALI_TYPE_REGISTRATION_END()
64 const Pixel::Format EFFECTS_VIEW_DEFAULT_PIXEL_FORMAT = Pixel::RGBA8888;
65 const float ARBITRARY_FIELD_OF_VIEW = Math::PI / 4.0f;
66 const Vector4 EFFECTS_VIEW_DEFAULT_BACKGROUND_COLOR( 0.0f, 0.0f, 0.0f, 0.0 );
67 const bool EFFECTS_VIEW_REFRESH_ON_DEMAND(false);
69 #define DALI_COMPOSE_SHADER(STR) #STR
71 const char* EFFECTS_VIEW_VERTEX_SOURCE = DALI_COMPOSE_SHADER(
72 attribute mediump vec2 aPosition;\n
73 varying mediump vec2 vTexCoord;\n
74 uniform mediump mat4 uMvpMatrix;\n
75 uniform mediump vec3 uSize;\n
76 uniform mediump vec3 effectOffset;\n
80 mediump vec4 vertexPosition = vec4(aPosition, 0.0, 1.0);\n
81 vertexPosition.xyz *= uSize;\n
82 vertexPosition.xyz += effectOffset;\n
83 vertexPosition = uMvpMatrix * vertexPosition;\n
85 vTexCoord = aPosition + vec2(0.5);\n
86 gl_Position = vertexPosition;\n
90 const char* EFFECTS_VIEW_FRAGMENT_SOURCE = DALI_COMPOSE_SHADER(
91 varying mediump vec2 vTexCoord;\n
92 uniform sampler2D sTexture;\n
93 uniform lowp vec4 effectColor;\n
97 gl_FragColor = effectColor;\n
98 gl_FragColor.a *= texture2D( sTexture, vTexCoord).a;\n
102 const float BLUR_KERNEL0[] = { 12.0f/16.0f,
103 2.0f/16.0f, 2.0f/16.0f };
105 const float BLUR_KERNEL1[] = { 8.0f/16.0f,
106 4.0f/16.0f, 4.0f/16.0f };
108 const float BLUR_KERNEL2[] = { 6.0f/16.0f,
109 2.5f/16.0f, 2.5f/16.0f,
110 1.5f/16.0f, 1.5f/16.0f,
111 1.0f/16.0f, 1.0f/16.0f };
113 const float BLUR_KERNEL3[] = { 4.0f/16.0f,
114 3.0f/16.0f, 2.0f/16.0f,
115 2.0f/16.0f, 2.0f/16.0f,
116 1.0f/16.0f, 1.0f/16.0f };
118 const float BLUR_KERNEL4[] = { 3.0f/16.0f,
119 2.5f/16.0f, 2.5f/16.0f,
120 1.75f/16.0f, 1.75f/16.0f,
121 1.25f/16.0f, 1.25f/16.0f,
122 1.0f/16.0f, 1.0f/16.0f };
126 Toolkit::EffectsView EffectsView::New()
128 EffectsView* effectsView = new EffectsView;
130 Toolkit::EffectsView handle = Toolkit::EffectsView( *effectsView );
132 // Second-phase init of the implementation
133 // This can only be done after the CustomActor connection has been made...
134 effectsView->Initialize();
139 EffectsView::EffectsView()
140 : Control( ControlBehaviour( CONTROL_BEHAVIOUR_DEFAULT ) ),
141 mChildrenRoot(Actor::New()),
142 mBackgroundColor( EFFECTS_VIEW_DEFAULT_BACKGROUND_COLOR ),
143 mTargetSize( Vector2::ZERO ),
144 mLastSize( Vector2::ZERO ),
146 mEffectType( Toolkit::EffectsView::INVALID_TYPE ),
147 mPixelFormat( EFFECTS_VIEW_DEFAULT_PIXEL_FORMAT ),
149 mRefreshOnDemand( EFFECTS_VIEW_REFRESH_ON_DEMAND )
151 DevelControl::SetAccessibilityConstructor( Self(), []( Dali::Actor actor ) {
152 return std::unique_ptr< Dali::Accessibility::Accessible >(
153 new Control::Impl::AccessibleImpl( actor, Dali::Accessibility::Role::FILLER ) );
157 EffectsView::~EffectsView()
162 void EffectsView::SetType( Toolkit::EffectsView::EffectType type )
164 if( mEffectType != type )
172 case Toolkit::EffectsView::DROP_SHADOW:
174 mFilters.PushBack( new SpreadFilter );
175 mFilters.PushBack( new BlurTwoPassFilter );
178 case Toolkit::EffectsView::EMBOSS:
180 mFilters.PushBack( new SpreadFilter );
181 mFilters.PushBack( new EmbossFilter );
182 mFilters.PushBack( new BlurTwoPassFilter );
195 Toolkit::EffectsView::EffectType EffectsView::GetType() const
200 void EffectsView::Enable()
202 // make sure resources are allocated and start the render tasks processing
208 void EffectsView::Disable()
210 // stop render tasks processing
212 mLastSize = Vector2::ZERO; // Ensure resources are reallocated on subsequent enable
216 void EffectsView::Refresh()
218 RefreshRenderTasks();
221 void EffectsView::SetRefreshOnDemand( bool onDemand )
223 mRefreshOnDemand = onDemand;
225 RefreshRenderTasks();
228 void EffectsView::SetPixelFormat( Pixel::Format pixelFormat )
230 mPixelFormat = pixelFormat;
233 void EffectsView::SetBackgroundColor( const Vector4& color )
235 mBackgroundColor = color;
238 Vector4 EffectsView::GetBackgroundColor() const
240 return mBackgroundColor;
243 void EffectsView::SetEffectSize( int effectSize )
245 mEffectSize = effectSize;
249 const size_t numFilters( mFilters.Size() );
250 for( size_t i = 0; i < numFilters; ++i )
252 mFilters[i]->Disable();
257 for( size_t i = 0; i < numFilters; ++i )
259 mFilters[i]->Enable();
264 int EffectsView::GetEffectSize()
270 void EffectsView::OnInitialize()
272 CustomActor self = Self();
273 mChildrenRoot.SetProperty( Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER );
274 self.Add( mChildrenRoot );
277 void EffectsView::OnSizeSet(const Vector3& targetSize)
279 mTargetSize = Vector2(targetSize);
281 // if we are already on stage, need to update render target sizes now to reflect the new size of this actor
284 if( mLastSize != Vector2::ZERO )
291 mChildrenRoot.SetProperty( Actor::Property::SIZE, targetSize );
293 Control::OnSizeSet( targetSize );
296 void EffectsView::OnSceneConnection( int depth )
298 Actor self( Self() );
301 mRendererPostFilter = CreateRenderer( EFFECTS_VIEW_VERTEX_SOURCE, EFFECTS_VIEW_FRAGMENT_SOURCE );
302 mRendererPostFilter.SetProperty( Dali::Renderer::Property::DEPTH_INDEX, DepthIndex::CONTENT );
303 self.AddRenderer( mRendererPostFilter );
305 mRendererForChildren = CreateRenderer( BASIC_VERTEX_SOURCE, BASIC_FRAGMENT_SOURCE );
306 mRendererForChildren.SetProperty( Dali::Renderer::Property::DEPTH_INDEX, DepthIndex::CONTENT + 1 );
307 self.AddRenderer( mRendererForChildren );
311 Control::OnSceneConnection( depth );
314 void EffectsView::OnSceneDisconnection()
316 Actor self( Self() );
320 const size_t numFilters( mFilters.Size() );
321 for( size_t i = 0; i < numFilters; ++i )
323 mFilters[i]->Disable();
327 self.RemoveRenderer( mRendererForChildren );
328 mRendererForChildren.Reset();
330 self.RemoveRenderer( mRendererPostFilter );
331 mRendererPostFilter.Reset();
333 Control::OnSceneDisconnection();
336 void EffectsView::OnChildAdd( Actor& child )
338 if( child != mChildrenRoot && child != mCameraForChildren )
340 mChildrenRoot.Add( child );
343 Control::OnChildAdd( child );
346 void EffectsView::OnChildRemove( Actor& child )
348 mChildrenRoot.Remove( child );
350 Control::OnChildRemove( child );
353 void EffectsView::SetupFilters()
355 switch( mEffectType )
357 case Toolkit::EffectsView::DROP_SHADOW:
359 SpreadFilter* spreadFilter = static_cast< SpreadFilter* >( mFilters[0] );
360 spreadFilter->SetInputTexture( mFrameBufferForChildren.GetColorTexture() );
361 spreadFilter->SetOutputFrameBuffer( mFrameBufferPostFilter );
362 spreadFilter->SetRootActor( mChildrenRoot );
363 spreadFilter->SetBackgroundColor( mBackgroundColor );
364 spreadFilter->SetPixelFormat( mPixelFormat );
365 spreadFilter->SetSize( mTargetSize );
366 spreadFilter->SetSpread( mEffectSize );
368 BlurTwoPassFilter* blurFilter = static_cast< BlurTwoPassFilter* >( mFilters[1] );
369 blurFilter->SetInputTexture( mFrameBufferPostFilter.GetColorTexture() );
370 blurFilter->SetOutputFrameBuffer( mFrameBufferPostFilter );
371 blurFilter->SetRootActor( mChildrenRoot );
372 blurFilter->SetBackgroundColor( mBackgroundColor );
373 blurFilter->SetPixelFormat( mPixelFormat );
374 blurFilter->SetSize( mTargetSize );
376 const float* kernel(NULL);
377 size_t kernelSize(0);
378 switch( mEffectSize )
380 case 4: { kernel = BLUR_KERNEL4; kernelSize = sizeof(BLUR_KERNEL4)/sizeof(BLUR_KERNEL4[0]); break; }
381 case 3: { kernel = BLUR_KERNEL3; kernelSize = sizeof(BLUR_KERNEL3)/sizeof(BLUR_KERNEL3[0]); break; }
382 case 2: { kernel = BLUR_KERNEL2; kernelSize = sizeof(BLUR_KERNEL2)/sizeof(BLUR_KERNEL2[0]); break; }
383 case 1: { kernel = BLUR_KERNEL1; kernelSize = sizeof(BLUR_KERNEL1)/sizeof(BLUR_KERNEL1[0]); break; }
385 default: { kernel = BLUR_KERNEL0; kernelSize = sizeof(BLUR_KERNEL0)/sizeof(BLUR_KERNEL0[0]); break; }
387 blurFilter->CreateKernel( kernel, kernelSize );
390 case Toolkit::EffectsView::EMBOSS:
392 SpreadFilter* spreadFilter = static_cast< SpreadFilter* >( mFilters[0] );
393 spreadFilter->SetInputTexture( mFrameBufferForChildren.GetColorTexture() );
394 spreadFilter->SetOutputFrameBuffer( mFrameBufferPostFilter );
395 spreadFilter->SetRootActor( mChildrenRoot );
396 spreadFilter->SetBackgroundColor( mBackgroundColor );
397 spreadFilter->SetPixelFormat( Pixel::RGBA8888 );
398 spreadFilter->SetSize( mTargetSize );
399 spreadFilter->SetSpread( mEffectSize );
401 EmbossFilter* embossFilter = static_cast< EmbossFilter* >( mFilters[1] );
402 embossFilter->SetInputTexture( mFrameBufferPostFilter.GetColorTexture() );
403 embossFilter->SetOutputFrameBuffer( mFrameBufferPostFilter );
404 embossFilter->SetRootActor( mChildrenRoot );
405 embossFilter->SetBackgroundColor( mBackgroundColor );
406 embossFilter->SetPixelFormat( Pixel::RGBA8888 );
407 embossFilter->SetSize( mTargetSize );
409 BlurTwoPassFilter* blurFilter = static_cast< BlurTwoPassFilter* >( mFilters[2] );
410 blurFilter->SetInputTexture( mFrameBufferPostFilter.GetColorTexture() );
411 blurFilter->SetOutputFrameBuffer( mFrameBufferPostFilter );
412 blurFilter->SetRootActor( mChildrenRoot );
413 blurFilter->SetBackgroundColor( Vector4( 0.5f, 0.5f, 0.5f, 0.0 ) );
414 blurFilter->SetPixelFormat( Pixel::RGBA8888 );
415 blurFilter->SetSize( mTargetSize );
416 blurFilter->CreateKernel( BLUR_KERNEL0, sizeof(BLUR_KERNEL0)/sizeof(BLUR_KERNEL0[0]) );
427 void EffectsView::AllocateResources()
429 if(mTargetSize != mLastSize)
431 mLastSize = mTargetSize;
434 Actor self( Self() );
436 mFrameBufferForChildren = FrameBuffer::New( mTargetSize.width, mTargetSize.height, FrameBuffer::Attachment::NONE );
437 Texture textureForChildren = Texture::New( TextureType::TEXTURE_2D, mPixelFormat, unsigned(mTargetSize.width), unsigned(mTargetSize.height) );
438 mFrameBufferForChildren.AttachColorTexture( textureForChildren );
440 SetRendererTexture( mRendererForChildren, textureForChildren );
442 mFrameBufferPostFilter = FrameBuffer::New( mTargetSize.width, mTargetSize.height, FrameBuffer::Attachment::NONE );
443 Texture texturePostFilter = Texture::New( TextureType::TEXTURE_2D, mPixelFormat, unsigned(mTargetSize.width), unsigned(mTargetSize.height) );
444 mFrameBufferPostFilter.AttachColorTexture( texturePostFilter );
446 SetRendererTexture( mRendererPostFilter, texturePostFilter );
452 void EffectsView::SetupCameras()
454 if( !mCameraForChildren )
456 // Create a camera for the children render, corresponding to its render target size
457 mCameraForChildren = CameraActor::New(mTargetSize);
458 mCameraForChildren.SetProperty( Actor::Property::PARENT_ORIGIN,ParentOrigin::CENTER );
459 mCameraForChildren.SetInvertYAxis( true );
460 Self().Add( mCameraForChildren );
464 // place the camera for the children render, corresponding to its render target size
465 const float cameraPosScale( 0.5f / tanf(ARBITRARY_FIELD_OF_VIEW * 0.5f) );
466 mCameraForChildren.SetFieldOfView(ARBITRARY_FIELD_OF_VIEW);
467 mCameraForChildren.SetNearClippingPlane(1.0f);
468 mCameraForChildren.SetAspectRatio(mTargetSize.width / mTargetSize.height);
469 mCameraForChildren.SetType(Dali::Camera::FREE_LOOK); // camera orientation based solely on actor
470 mCameraForChildren.SetProperty( Actor::Property::POSITION, Vector3( 0.0f, 0.0f, mTargetSize.height * cameraPosScale ) );
471 mCameraForChildren.SetProperty( Actor::Property::POSITION_Z, mTargetSize.height * cameraPosScale );
475 void EffectsView::CreateRenderTasks()
477 if( mTargetSize == Vector2::ZERO )
481 RenderTaskList taskList = Stage::GetCurrent().GetRenderTaskList();
483 // create render task to render our child actors to offscreen buffer
484 mRenderTaskForChildren = taskList.CreateTask();
485 mRenderTaskForChildren.SetRefreshRate( mRefreshOnDemand ? RenderTask::REFRESH_ONCE : RenderTask::REFRESH_ALWAYS );
486 mRenderTaskForChildren.SetSourceActor( mChildrenRoot );
487 mRenderTaskForChildren.SetExclusive(true);
488 mRenderTaskForChildren.SetInputEnabled( false );
489 mRenderTaskForChildren.SetClearColor( mBackgroundColor );
490 mRenderTaskForChildren.SetClearEnabled( true );
491 mRenderTaskForChildren.SetFrameBuffer( mFrameBufferForChildren );
492 mRenderTaskForChildren.SetCameraActor(mCameraForChildren); // use camera that covers render target exactly
494 // Enable image filters
495 const size_t numFilters( mFilters.Size() );
496 for( size_t i = 0; i < numFilters; ++i )
498 mFilters[i]->Enable();
502 void EffectsView::RemoveRenderTasks()
504 if( mTargetSize == Vector2::ZERO )
509 RenderTaskList taskList = Stage::GetCurrent().GetRenderTaskList();
511 taskList.RemoveTask(mRenderTaskForChildren);
513 const size_t numFilters( mFilters.Size() );
514 for( size_t i = 0; i < numFilters; ++i )
516 mFilters[i]->Disable();
520 void EffectsView::RefreshRenderTasks()
522 RenderTaskList taskList = Stage::GetCurrent().GetRenderTaskList();
524 if( mRenderTaskForChildren )
526 mRenderTaskForChildren.SetRefreshRate( mRefreshOnDemand ? RenderTask::REFRESH_ONCE : RenderTask::REFRESH_ALWAYS );
529 const size_t numFilters( mFilters.Size() );
530 for( size_t i = 0; i < numFilters; ++i )
532 mFilters[i]->Refresh();
536 void EffectsView::RemoveFilters()
538 const size_t numFilters( mFilters.Size() );
539 for( size_t i = 0; i < numFilters; ++i )
546 void EffectsView::SetProperty( BaseObject* object, Property::Index index, const Property::Value& value )
548 Toolkit::EffectsView effectsView = Toolkit::EffectsView::DownCast( Dali::BaseHandle( object ) );
554 case Toolkit::EffectsView::Property::EFFECT_SIZE:
557 if( value.Get( effectSize ) )
559 GetImpl( effectsView ).SetEffectSize( effectSize );
571 Property::Value EffectsView::GetProperty( BaseObject* object, Property::Index propertyIndex )
573 Property::Value value;
575 Toolkit::EffectsView imageview = Toolkit::EffectsView::DownCast( Dali::BaseHandle( object ) );
579 EffectsView& impl = GetImpl( imageview );
580 switch ( propertyIndex )
582 case Toolkit::EffectsView::Property::EFFECT_SIZE:
584 value = impl.GetEffectSize();
597 } // namespace Internal
599 } // namespace Toolkit