2 * Copyright (c) 2017 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/public-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>
31 #include <dali/devel-api/images/texture-set-image.h>
34 #include <dali-toolkit/public-api/visuals/visual-properties.h>
35 #include <dali-toolkit/devel-api/controls/control-depth-index-ranges.h>
36 #include <dali-toolkit/devel-api/controls/control-devel.h>
37 #include <dali-toolkit/devel-api/visual-factory/visual-factory.h>
38 #include <dali-toolkit/internal/filters/blur-two-pass-filter.h>
39 #include <dali-toolkit/internal/filters/emboss-filter.h>
40 #include <dali-toolkit/internal/filters/spread-filter.h>
41 #include <dali-toolkit/internal/visuals/visual-base-impl.h>
42 #include <dali-toolkit/internal/visuals/visual-factory-impl.h>
56 Dali::BaseHandle Create()
58 return EffectsView::New();
61 DALI_TYPE_REGISTRATION_BEGIN( Toolkit::EffectsView, Toolkit::Control, Create )
62 DALI_PROPERTY_REGISTRATION( Toolkit, EffectsView, "effectSize", INTEGER, EFFECT_SIZE )
63 DALI_ANIMATABLE_PROPERTY_REGISTRATION( Toolkit, EffectsView, "effectOffset", VECTOR3, EFFECT_OFFSET )
64 DALI_ANIMATABLE_PROPERTY_REGISTRATION_WITH_DEFAULT( Toolkit, EffectsView, "effectColor", Color::WHITE, EFFECT_COLOR )
65 DALI_TYPE_REGISTRATION_END()
67 const Pixel::Format EFFECTS_VIEW_DEFAULT_PIXEL_FORMAT = Pixel::RGBA8888;
68 const float ARBITRARY_FIELD_OF_VIEW = Math::PI / 4.0f;
69 const Vector4 EFFECTS_VIEW_DEFAULT_BACKGROUND_COLOR( 1.0f, 1.0f, 1.0f, 0.0 );
70 const bool EFFECTS_VIEW_REFRESH_ON_DEMAND(false);
72 // Visuals are not stylable or public
73 const Property::Index CHILD_VISUAL( Toolkit::EffectsView::ANIMATABLE_PROPERTY_START_INDEX - 1);
74 const Property::Index POST_FILTER_VISUAL( CHILD_VISUAL-1 );
76 #define DALI_COMPOSE_SHADER(STR) #STR
78 const char* EFFECTS_VIEW_VERTEX_SOURCE = DALI_COMPOSE_SHADER(
79 attribute mediump vec2 aPosition;\n
80 varying mediump vec2 vTexCoord;\n
81 uniform mediump mat4 uMvpMatrix;\n
82 uniform mediump vec3 uSize;\n
83 uniform mediump vec3 effectOffset;\n
87 mediump vec4 vertexPosition = vec4(aPosition, 0.0, 1.0);\n
88 vertexPosition.xyz *= uSize;\n
89 vertexPosition.xyz += effectOffset;\n
90 vertexPosition = uMvpMatrix * vertexPosition;\n
92 vTexCoord = aPosition + vec2(0.5);\n
93 gl_Position = vertexPosition;\n
97 const char* EFFECTS_VIEW_FRAGMENT_SOURCE = DALI_COMPOSE_SHADER(
98 varying mediump vec2 vTexCoord;\n
99 uniform sampler2D sTexture;\n
100 uniform lowp vec4 effectColor;\n
104 gl_FragColor = effectColor;\n
105 gl_FragColor.a *= texture2D( sTexture, vTexCoord).a;\n
109 const float BLUR_KERNEL0[] = { 12.0f/16.0f,
110 2.0f/16.0f, 2.0f/16.0f };
112 const float BLUR_KERNEL1[] = { 8.0f/16.0f,
113 4.0f/16.0f, 4.0f/16.0f };
115 const float BLUR_KERNEL2[] = { 6.0f/16.0f,
116 2.5f/16.0f, 2.5f/16.0f,
117 1.5f/16.0f, 1.5f/16.0f,
118 1.0f/16.0f, 1.0f/16.0f };
120 const float BLUR_KERNEL3[] = { 4.0f/16.0f,
121 3.0f/16.0f, 2.0f/16.0f,
122 2.0f/16.0f, 2.0f/16.0f,
123 1.0f/16.0f, 1.0f/16.0f };
125 const float BLUR_KERNEL4[] = { 3.0f/16.0f,
126 2.5f/16.0f, 2.5f/16.0f,
127 1.75f/16.0f, 1.75f/16.0f,
128 1.25f/16.0f, 1.25f/16.0f,
129 1.0f/16.0f, 1.0f/16.0f };
133 Toolkit::EffectsView EffectsView::New()
135 EffectsView* effectsView = new EffectsView;
137 Toolkit::EffectsView handle = Toolkit::EffectsView( *effectsView );
139 // Second-phase init of the implementation
140 // This can only be done after the CustomActor connection has been made...
141 effectsView->Initialize();
146 EffectsView::EffectsView()
147 : Control( ControlBehaviour( CONTROL_BEHAVIOUR_DEFAULT ) ),
148 mChildrenRoot(Actor::New()),
149 mBackgroundColor( EFFECTS_VIEW_DEFAULT_BACKGROUND_COLOR ),
150 mTargetSize( Vector2::ZERO ),
151 mLastSize( Vector2::ZERO ),
153 mEffectType( Toolkit::EffectsView::INVALID_TYPE ),
154 mPixelFormat( EFFECTS_VIEW_DEFAULT_PIXEL_FORMAT ),
156 mRefreshOnDemand(EFFECTS_VIEW_REFRESH_ON_DEMAND)
160 EffectsView::~EffectsView()
165 void EffectsView::SetType( Toolkit::EffectsView::EffectType type )
167 if( mEffectType != type )
175 case Toolkit::EffectsView::DROP_SHADOW:
177 mFilters.PushBack( new SpreadFilter );
178 mFilters.PushBack( new BlurTwoPassFilter );
181 case Toolkit::EffectsView::EMBOSS:
183 mFilters.PushBack( new SpreadFilter );
184 mFilters.PushBack( new EmbossFilter );
185 mFilters.PushBack( new BlurTwoPassFilter );
194 FrameBufferImage dummyImage = FrameBufferImage::New( mTargetSize.width, mTargetSize.height, mPixelFormat );
196 Internal::InitializeVisual( self, mVisualPostFilter, dummyImage );
197 DevelControl::RegisterVisual( *this, POST_FILTER_VISUAL, mVisualPostFilter );
199 Property::Map customShader;
200 customShader[ Toolkit::Visual::Shader::Property::VERTEX_SHADER ] = EFFECTS_VIEW_VERTEX_SOURCE;
201 customShader[ Toolkit::Visual::Shader::Property::FRAGMENT_SHADER ] = EFFECTS_VIEW_FRAGMENT_SOURCE;
202 Toolkit::GetImplementation( mVisualPostFilter ).SetCustomShader( customShader );
208 Toolkit::EffectsView::EffectType EffectsView::GetType() const
213 void EffectsView::Enable()
215 // make sure resources are allocated and start the render tasks processing
221 void EffectsView::Disable()
223 // stop render tasks processing
224 // Note: render target resources are automatically freed since we set the Image::Unused flag
226 mLastSize = Vector2::ZERO; // Ensure resources are reallocated on subsequent enable
230 void EffectsView::Refresh()
232 RefreshRenderTasks();
235 void EffectsView::SetRefreshOnDemand( bool onDemand )
237 mRefreshOnDemand = onDemand;
239 RefreshRenderTasks();
242 void EffectsView::SetPixelFormat( Pixel::Format pixelFormat )
244 mPixelFormat = pixelFormat;
247 void EffectsView::SetBackgroundColor( const Vector4& color )
249 mBackgroundColor = color;
252 Vector4 EffectsView::GetBackgroundColor() const
254 return mBackgroundColor;
257 void EffectsView::SetEffectSize( int effectSize )
259 mEffectSize = effectSize;
263 const size_t numFilters( mFilters.Size() );
264 for( size_t i = 0; i < numFilters; ++i )
266 mFilters[i]->Disable();
271 for( size_t i = 0; i < numFilters; ++i )
273 mFilters[i]->Enable();
278 int EffectsView::GetEffectSize()
284 void EffectsView::OnInitialize()
286 CustomActor self = Self();
287 mChildrenRoot.SetParentOrigin( ParentOrigin::CENTER );
288 self.Add( mChildrenRoot );
291 void EffectsView::OnSizeSet(const Vector3& targetSize)
293 mTargetSize = Vector2(targetSize);
295 // if we are already on stage, need to update render target sizes now to reflect the new size of this actor
298 if( mLastSize != Vector2::ZERO )
305 mChildrenRoot.SetSize( targetSize );
307 Control::OnSizeSet( targetSize );
310 void EffectsView::OnStageConnection( int depth )
314 Control::OnStageConnection( depth );
317 void EffectsView::OnStageDisconnection()
321 const size_t numFilters( mFilters.Size() );
322 for( size_t i = 0; i < numFilters; ++i )
324 mFilters[i]->Disable();
327 Control::OnStageDisconnection();
330 void EffectsView::OnChildAdd( Actor& child )
332 if( child != mChildrenRoot && child != mCameraForChildren )
334 mChildrenRoot.Add( child );
337 Control::OnChildAdd( child );
340 void EffectsView::OnChildRemove( Actor& child )
342 mChildrenRoot.Remove( child );
344 Control::OnChildRemove( child );
347 void EffectsView::SetupFilters()
349 switch( mEffectType )
351 case Toolkit::EffectsView::DROP_SHADOW:
353 SpreadFilter* spreadFilter = static_cast< SpreadFilter* >( mFilters[0] );
354 spreadFilter->SetInputImage( mImageForChildren );
355 spreadFilter->SetOutputImage( mImagePostFilter );
356 spreadFilter->SetRootActor( mChildrenRoot );
357 spreadFilter->SetBackgroundColor( mBackgroundColor );
358 spreadFilter->SetPixelFormat( mPixelFormat );
359 spreadFilter->SetSize( mTargetSize );
360 spreadFilter->SetSpread( mEffectSize );
362 BlurTwoPassFilter* blurFilter = static_cast< BlurTwoPassFilter* >( mFilters[1] );
363 blurFilter->SetInputImage( mImagePostFilter );
364 blurFilter->SetOutputImage( mImagePostFilter );
365 blurFilter->SetRootActor( mChildrenRoot );
366 blurFilter->SetBackgroundColor( mBackgroundColor );
367 blurFilter->SetPixelFormat( mPixelFormat );
368 blurFilter->SetSize( mTargetSize );
370 const float* kernel(NULL);
371 size_t kernelSize(0);
372 switch( mEffectSize )
374 case 4: { kernel = BLUR_KERNEL4; kernelSize = sizeof(BLUR_KERNEL4)/sizeof(BLUR_KERNEL4[0]); break; }
375 case 3: { kernel = BLUR_KERNEL3; kernelSize = sizeof(BLUR_KERNEL3)/sizeof(BLUR_KERNEL3[0]); break; }
376 case 2: { kernel = BLUR_KERNEL2; kernelSize = sizeof(BLUR_KERNEL2)/sizeof(BLUR_KERNEL2[0]); break; }
377 case 1: { kernel = BLUR_KERNEL1; kernelSize = sizeof(BLUR_KERNEL1)/sizeof(BLUR_KERNEL1[0]); break; }
379 default: { kernel = BLUR_KERNEL0; kernelSize = sizeof(BLUR_KERNEL0)/sizeof(BLUR_KERNEL0[0]); break; }
381 blurFilter->CreateKernel( kernel, kernelSize );
384 case Toolkit::EffectsView::EMBOSS:
386 SpreadFilter* spreadFilter = static_cast< SpreadFilter* >( mFilters[0] );
387 spreadFilter->SetInputImage( mImageForChildren );
388 spreadFilter->SetOutputImage( mImagePostFilter );
389 spreadFilter->SetRootActor( mChildrenRoot );
390 spreadFilter->SetBackgroundColor( mBackgroundColor );
391 spreadFilter->SetPixelFormat( Pixel::RGBA8888 );
392 spreadFilter->SetSize( mTargetSize );
393 spreadFilter->SetSpread( mEffectSize );
395 EmbossFilter* embossFilter = static_cast< EmbossFilter* >( mFilters[1] );
396 embossFilter->SetInputImage( mImagePostFilter );
397 embossFilter->SetOutputImage( mImagePostFilter );
398 embossFilter->SetRootActor( mChildrenRoot );
399 embossFilter->SetBackgroundColor( mBackgroundColor );
400 embossFilter->SetPixelFormat( Pixel::RGBA8888 );
401 embossFilter->SetSize( mTargetSize );
403 BlurTwoPassFilter* blurFilter = static_cast< BlurTwoPassFilter* >( mFilters[2] );
404 blurFilter->SetInputImage( mImagePostFilter );
405 blurFilter->SetOutputImage( mImagePostFilter );
406 blurFilter->SetRootActor( mChildrenRoot );
407 blurFilter->SetBackgroundColor( Vector4( 0.5f, 0.5f, 0.5f, 0.0 ) );
408 blurFilter->SetPixelFormat( Pixel::RGBA8888 );
409 blurFilter->SetSize( mTargetSize );
410 blurFilter->CreateKernel( BLUR_KERNEL0, sizeof(BLUR_KERNEL0)/sizeof(BLUR_KERNEL0[0]) );
420 void EffectsView::AllocateResources()
422 if(mTargetSize != mLastSize)
424 mLastSize = mTargetSize;
427 Actor self( Self() );
429 mImageForChildren = FrameBufferImage::New( mTargetSize.width, mTargetSize.height, mPixelFormat );
430 Internal::InitializeVisual( self, mVisualForChildren, mImageForChildren );
431 DevelControl::RegisterVisual( *this, CHILD_VISUAL, mVisualForChildren );
432 mVisualForChildren.SetDepthIndex( DepthIndex::CONTENT+1 );
434 mImagePostFilter = FrameBufferImage::New( mTargetSize.width, mTargetSize.height, mPixelFormat );
435 TextureSet textureSet = TextureSet::New();
436 TextureSetImage( textureSet, 0u, mImagePostFilter );
437 self.GetRendererAt( 0 ).SetTextures( textureSet );
438 mVisualPostFilter.SetDepthIndex( DepthIndex::CONTENT );
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.SetParentOrigin(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.SetPosition(0.0f, 0.0f, mTargetSize.height * cameraPosScale);
463 mCameraForChildren.SetZ( 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.SetTargetFrameBuffer( mImageForChildren );
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