2 * Copyright (c) 2014 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/active-constraint.h>
23 #include <dali/public-api/animation/constraint.h>
24 #include <dali/public-api/animation/constraints.h>
25 #include <dali/public-api/common/stage.h>
26 #include <dali/public-api/object/type-registry.h>
27 #include <dali/public-api/object/type-registry-helper.h>
28 #include <dali/public-api/render-tasks/render-task-list.h>
31 #include "../../filters/blur-two-pass-filter.h"
32 #include "../../filters/emboss-filter.h"
33 #include "../../filters/spread-filter.h"
47 Dali::BaseHandle Create()
49 return Toolkit::EffectsView::New();
52 DALI_TYPE_REGISTRATION_BEGIN( Toolkit::EffectsView, Toolkit::Control, Create )
53 DALI_TYPE_REGISTRATION_END()
55 const Pixel::Format EFFECTS_VIEW_DEFAULT_PIXEL_FORMAT = Pixel::RGBA8888;
56 const float ARBITRARY_FIELD_OF_VIEW = Math::PI / 4.0f;
57 const Vector4 EFFECTS_VIEW_DEFAULT_BACKGROUND_COLOR( 1.0f, 1.0f, 1.0f, 0.0 );
58 const bool EFFECTS_VIEW_REFRESH_ON_DEMAND(false);
61 const char* const EFFECT_SIZE_PROPERTY_NAME = "EffectSize";
62 const char* const EFFECT_STRENGTH_PROPERTY_NAME = "EffectStrength";
63 const char* const EFFECT_OFFSET_PROPERTY_NAME = "EffectOffset";
64 const char* const EFFECT_COLOR_PROPERTY_NAME = "EffectColor";
66 const float EFFECT_SIZE_DEFAULT( 1.0f );
67 const float EFFECT_STRENGTH_DEFAULT( 0.5f );
68 const Vector3 EFFECT_OFFSET_DEFAULT( 0.0f, 0.0f, 0.0f );
69 const Vector4 EFFECT_COLOR_DEFAULT( Color::WHITE );
71 const char* const EFFECTS_VIEW_FRAGMENT_SOURCE =
74 " gl_FragColor = uColor;\n"
75 " gl_FragColor.a *= texture2D( sTexture, vTexCoord).a;\n"
78 const float BLUR_KERNEL0[] = { 12.0f/16.0f,
79 2.0f/16.0f, 2.0f/16.0f };
81 const float BLUR_KERNEL1[] = { 8.0f/16.0f,
82 4.0f/16.0f, 4.0f/16.0f };
84 const float BLUR_KERNEL2[] = { 6.0f/16.0f,
85 2.5f/16.0f, 2.5f/16.0f,
86 1.5f/16.0f, 1.5f/16.0f,
87 1.0f/16.0f, 1.0f/16.0f };
89 const float BLUR_KERNEL3[] = { 4.0f/16.0f,
90 3.0f/16.0f, 2.0f/16.0f,
91 2.0f/16.0f, 2.0f/16.0f,
92 1.0f/16.0f, 1.0f/16.0f };
94 const float BLUR_KERNEL4[] = { 3.0f/16.0f,
95 2.5f/16.0f, 2.5f/16.0f,
96 1.75f/16.0f, 1.75f/16.0f,
97 1.25f/16.0f, 1.25f/16.0f,
98 1.0f/16.0f, 1.0f/16.0f };
102 Toolkit::EffectsView EffectsView::New()
104 EffectsView* effectsView = new EffectsView;
106 Toolkit::EffectsView handle = Toolkit::EffectsView( *effectsView );
108 // Second-phase init of the implementation
109 // This can only be done after the CustomActor connection has been made...
110 effectsView->Initialize();
115 EffectsView::EffectsView()
116 : Control( CONTROL_BEHAVIOUR_NONE ),
117 mEffectType( Toolkit::EffectsView::INVALID_TYPE ),
118 mPixelFormat( EFFECTS_VIEW_DEFAULT_PIXEL_FORMAT ),
120 mBackgroundColor( EFFECTS_VIEW_DEFAULT_BACKGROUND_COLOR ),
121 mTargetSize( Vector2::ZERO ),
122 mLastSize( Vector2::ZERO ),
123 mRefreshOnDemand(EFFECTS_VIEW_REFRESH_ON_DEMAND),
124 mEffectSizePropertyIndex(Property::INVALID_INDEX),
125 mEffectStrengthPropertyIndex(Property::INVALID_INDEX),
126 mEffectOffsetPropertyIndex(Property::INVALID_INDEX),
127 mEffectColorPropertyIndex(Property::INVALID_INDEX)
131 EffectsView::~EffectsView()
136 void EffectsView::SetType( Toolkit::EffectsView::EffectType type )
138 if( mEffectType != type )
144 switch( mEffectType )
146 case Toolkit::EffectsView::DROP_SHADOW:
148 mFilters.push_back( new SpreadFilter );
149 mFilters.push_back( new BlurTwoPassFilter );
152 case Toolkit::EffectsView::EMBOSS:
154 mFilters.push_back( new SpreadFilter );
155 mFilters.push_back( new EmbossFilter );
156 mFilters.push_back( new BlurTwoPassFilter );
157 mActorPostFilter.RemoveShaderEffect();
168 Toolkit::EffectsView::EffectType EffectsView::GetType() const
173 void EffectsView::Enable()
175 // make sure resources are allocated and start the render tasks processing
180 void EffectsView::Disable()
182 // stop render tasks processing
183 // Note: render target resources are automatically freed since we set the Image::Unused flag
187 void EffectsView::Refresh()
189 RefreshRenderTasks();
192 void EffectsView::SetRefreshOnDemand( bool onDemand )
194 mRefreshOnDemand = onDemand;
196 RefreshRenderTasks();
199 void EffectsView::SetPixelFormat( Pixel::Format pixelFormat )
201 mPixelFormat = pixelFormat;
204 void EffectsView::SetOutputImage( FrameBufferImage image )
206 CustomActor self = Self();
208 if( mImageForResult != image )
212 if( mImageForResult )
214 self.Remove( mActorForResult );
215 mActorForResult.Reset();
217 self.Add( mActorPostFilter );
218 self.Add( mActorForChildren );
223 if( mImageForResult )
225 self.Remove( mActorForResult );
227 mActorForResult = Actor::New();
228 mActorForResult.SetParentOrigin( ParentOrigin::CENTER );
229 mActorForResult.SetSize( mTargetSize );
230 mActorForResult.ScaleBy( Vector3(1.0f, -1.0f, 1.0f) );
232 Self().Add( mActorForResult );
233 mActorForResult.Add( mActorPostFilter );
234 mActorForResult.Add( mActorForChildren );
236 mImageForResult = image;
240 FrameBufferImage EffectsView::GetOutputImage()
242 return mImageForResult;
245 Property::Index EffectsView::GetEffectSizePropertyIndex() const
247 return mEffectSizePropertyIndex;
250 Property::Index EffectsView::GetEffectStrengthPropertyIndex() const
252 return mEffectStrengthPropertyIndex;
255 Property::Index EffectsView::GetEffectOffsetPropertyIndex() const
257 return mEffectOffsetPropertyIndex;
260 Property::Index EffectsView::GetEffectColorPropertyIndex() const
262 return mEffectColorPropertyIndex;
265 void EffectsView::SetupProperties()
267 CustomActor self = Self();
269 // Register a property that the user can control the drop shadow offset
270 mEffectSizePropertyIndex = self.RegisterProperty(EFFECT_SIZE_PROPERTY_NAME, EFFECT_SIZE_DEFAULT, Property::READ_WRITE);
271 mEffectStrengthPropertyIndex = self.RegisterProperty(EFFECT_STRENGTH_PROPERTY_NAME, EFFECT_STRENGTH_DEFAULT, Property::READ_WRITE);
272 mEffectOffsetPropertyIndex = self.RegisterProperty(EFFECT_OFFSET_PROPERTY_NAME, EFFECT_OFFSET_DEFAULT);
273 mEffectColorPropertyIndex = self.RegisterProperty(EFFECT_COLOR_PROPERTY_NAME, EFFECT_COLOR_DEFAULT);
274 mActorPostFilter.ApplyConstraint( Constraint::New<Vector3>( Actor::Property::POSITION, Source( self, mEffectOffsetPropertyIndex ), EqualToConstraint() ) );
275 mActorPostFilter.ApplyConstraint( Constraint::New<Vector4>( Actor::Property::COLOR, Source( self, mEffectColorPropertyIndex ), EqualToConstraint() ) );
278 void EffectsView::SetBackgroundColor( const Vector4& color )
280 mBackgroundColor = color;
283 Vector4 EffectsView::GetBackgroundColor() const
285 return mBackgroundColor;
289 void EffectsView::OnInitialize()
291 //////////////////////////////////////////////////////
293 mCameraForChildren = CameraActor::New();
294 mCameraForChildren.SetParentOrigin(ParentOrigin::CENTER);
296 mActorForChildren = ImageActor::New();
297 mActorForChildren.SetPositionInheritanceMode( Dali::USE_PARENT_POSITION );
298 mActorForChildren.ScaleBy( Vector3(1.0f, -1.0f, 1.0f) );
300 mActorPostFilter = ImageActor::New();
301 mActorPostFilter.SetParentOrigin( ParentOrigin::CENTER );
302 mActorPostFilter.ScaleBy( Vector3(1.0f, -1.0f, 1.0f) );
303 mActorPostFilter.SetShaderEffect( ShaderEffect::New( "", EFFECTS_VIEW_FRAGMENT_SOURCE ) );
305 // Connect to actor tree
306 Self().Add( mActorPostFilter );
307 Self().Add( mActorForChildren );
308 Self().Add( mCameraForChildren );
313 void EffectsView::OnControlSizeSet(const Vector3& targetSize)
315 mTargetSize = Vector2(targetSize);
317 // if we are already on stage, need to update render target sizes now to reflect the new size of this actor
323 if( mActorForResult )
325 mActorForResult.SetSize( targetSize );
327 if( mActorForChildren )
329 mActorForChildren.SetSize( targetSize );
331 if( mActorPostFilter )
333 mActorPostFilter.SetSize( targetSize );
336 // Children render camera must move when EffectsView object is resized.
337 // This is since we cannot change render target size - so we need to remap the child actors' rendering
338 // accordingly so they still exactly fill the render target.
339 // Note that this means the effective resolution of the child render changes as the EffectsView object
340 // changes size, this is the trade off for not being able to modify render target size
341 // Change camera z position based on EffectsView actor height
342 if( mCameraForChildren )
344 const float cameraPosScale( 0.5f / tanf(ARBITRARY_FIELD_OF_VIEW * 0.5f) );
345 mCameraForChildren.SetZ( targetSize.height * cameraPosScale );
348 const size_t numFilters( mFilters.size() );
349 for( size_t i = 0; i < numFilters; ++i )
351 mFilters[i]->SetSize( mTargetSize );
356 void EffectsView::OnStageDisconnection()
358 const size_t numFilters( mFilters.size() );
359 for( size_t i = 0; i < numFilters; ++i )
361 mFilters[i]->Disable();
365 void EffectsView::SetupFilters()
367 int effectSize = static_cast< int >( Self().GetProperty( mEffectSizePropertyIndex ).Get<float>() );
368 switch( mEffectType )
370 case Toolkit::EffectsView::DROP_SHADOW:
372 SpreadFilter* spreadFilter = static_cast< SpreadFilter* >( mFilters[0] );
373 spreadFilter->SetInputImage( mImageForChildren );
374 spreadFilter->SetOutputImage( mImagePostFilter );
375 spreadFilter->SetRootActor( Self() );
376 spreadFilter->SetBackgroundColor( mBackgroundColor );
377 spreadFilter->SetPixelFormat( mPixelFormat );
378 spreadFilter->SetSize( mTargetSize );
379 spreadFilter->SetSpread( effectSize );
381 BlurTwoPassFilter* blurFilter = static_cast< BlurTwoPassFilter* >( mFilters[1] );
382 blurFilter->SetInputImage( mImagePostFilter );
383 blurFilter->SetOutputImage( mImagePostFilter );
384 blurFilter->SetRootActor( Self() );
385 blurFilter->SetBackgroundColor( mBackgroundColor );
386 blurFilter->SetPixelFormat( mPixelFormat );
387 blurFilter->SetSize( mTargetSize );
389 const float* kernel(NULL);
390 size_t kernelSize(0);
393 case 4: { kernel = BLUR_KERNEL4; kernelSize = sizeof(BLUR_KERNEL4)/sizeof(BLUR_KERNEL4[0]); break; }
394 case 3: { kernel = BLUR_KERNEL3; kernelSize = sizeof(BLUR_KERNEL3)/sizeof(BLUR_KERNEL3[0]); break; }
395 case 2: { kernel = BLUR_KERNEL2; kernelSize = sizeof(BLUR_KERNEL2)/sizeof(BLUR_KERNEL2[0]); break; }
396 case 1: { kernel = BLUR_KERNEL1; kernelSize = sizeof(BLUR_KERNEL1)/sizeof(BLUR_KERNEL1[0]); break; }
398 default: { kernel = BLUR_KERNEL0; kernelSize = sizeof(BLUR_KERNEL0)/sizeof(BLUR_KERNEL0[0]); break; }
400 blurFilter->CreateKernel( kernel, kernelSize );
403 case Toolkit::EffectsView::EMBOSS:
405 SpreadFilter* spreadFilter = static_cast< SpreadFilter* >( mFilters[0] );
406 spreadFilter->SetInputImage( mImageForChildren );
407 spreadFilter->SetOutputImage( mImagePostFilter );
408 spreadFilter->SetRootActor( Self() );
409 spreadFilter->SetBackgroundColor( mBackgroundColor );
410 spreadFilter->SetPixelFormat( Pixel::RGBA8888 );
411 spreadFilter->SetSize( mTargetSize );
412 spreadFilter->SetSpread( effectSize );
414 EmbossFilter* embossFilter = static_cast< EmbossFilter* >( mFilters[1] );
415 embossFilter->SetInputImage( mImagePostFilter );
416 embossFilter->SetOutputImage( mImagePostFilter );
417 embossFilter->SetRootActor( Self() );
418 embossFilter->SetBackgroundColor( mBackgroundColor );
419 embossFilter->SetPixelFormat( Pixel::RGBA8888 );
420 embossFilter->SetSize( mTargetSize );
422 BlurTwoPassFilter* blurFilter = static_cast< BlurTwoPassFilter* >( mFilters[2] );
423 blurFilter->SetInputImage( mImagePostFilter );
424 blurFilter->SetOutputImage( mImagePostFilter );
425 blurFilter->SetRootActor( Self() );
426 blurFilter->SetBackgroundColor( Vector4( 0.5f, 0.5f, 0.5f, 0.0 ) );
427 blurFilter->SetPixelFormat( Pixel::RGBA8888 );
428 blurFilter->SetSize( mTargetSize );
429 blurFilter->CreateKernel( BLUR_KERNEL0, sizeof(BLUR_KERNEL0)/sizeof(BLUR_KERNEL0[0]) );
439 void EffectsView::AllocateResources()
441 if(mTargetSize != mLastSize)
443 mLastSize = mTargetSize;
447 mImageForChildren = FrameBufferImage::New( mTargetSize.width, mTargetSize.height, mPixelFormat, Dali::Image::UNUSED );
448 mActorForChildren.SetImage(mImageForChildren);
450 mImagePostFilter = FrameBufferImage::New( mTargetSize.width, mTargetSize.height, mPixelFormat, Dali::Image::UNUSED );
451 mActorPostFilter.SetImage(mImagePostFilter);
457 void EffectsView::SetupCameras()
459 const float cameraPosScale( 0.5f / tanf(ARBITRARY_FIELD_OF_VIEW * 0.5f) );
461 // Create and place a camera for the children render, corresponding to its render target size
462 mCameraForChildren.SetFieldOfView(ARBITRARY_FIELD_OF_VIEW);
463 // TODO: how do we pick a reasonable value for near clip? Needs to relate to normal camera the user renders with, but we don't have a handle on it
464 mCameraForChildren.SetNearClippingPlane(1.0f);
465 mCameraForChildren.SetAspectRatio(mTargetSize.width / mTargetSize.height);
466 mCameraForChildren.SetType(Dali::Camera::FREE_LOOK); // camera orientation based solely on actor
467 mCameraForChildren.SetPosition(0.0f, 0.0f, mTargetSize.height * cameraPosScale);
468 mCameraForChildren.SetZ( mTargetSize.height * cameraPosScale );
471 void EffectsView::CreateRenderTasks()
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( Self() );
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();
493 // create render task to render result of the image filters to the final offscreen
494 if( mImageForResult )
496 mRenderTaskForResult = taskList.CreateTask();
497 mRenderTaskForResult.SetRefreshRate( mRefreshOnDemand ? RenderTask::REFRESH_ONCE : RenderTask::REFRESH_ALWAYS );
498 mRenderTaskForResult.SetSourceActor( mActorForResult );
499 mRenderTaskForResult.SetExclusive(true);
500 mRenderTaskForResult.SetInputEnabled( false );
501 mRenderTaskForResult.SetClearColor( mBackgroundColor );
502 mRenderTaskForResult.SetClearEnabled( true );
503 mRenderTaskForResult.SetTargetFrameBuffer( mImageForResult );
504 mRenderTaskForResult.SetCameraActor(mCameraForChildren); // use camera that covers render target exactly
508 void EffectsView::RemoveRenderTasks()
510 RenderTaskList taskList = Stage::GetCurrent().GetRenderTaskList();
512 taskList.RemoveTask(mRenderTaskForChildren);
513 taskList.RemoveTask(mRenderTaskForResult);
515 const size_t numFilters( mFilters.size() );
516 for( size_t i = 0; i < numFilters; ++i )
518 mFilters[i]->Disable();
522 void EffectsView::RefreshRenderTasks()
524 RenderTaskList taskList = Stage::GetCurrent().GetRenderTaskList();
526 if( mRenderTaskForChildren )
528 mRenderTaskForChildren.SetRefreshRate( mRefreshOnDemand ? RenderTask::REFRESH_ONCE : RenderTask::REFRESH_ALWAYS );
531 if( mRenderTaskForResult )
533 mRenderTaskForResult.SetRefreshRate( mRefreshOnDemand ? RenderTask::REFRESH_ONCE : RenderTask::REFRESH_ALWAYS );
536 const size_t numFilters( mFilters.size() );
537 for( size_t i = 0; i < numFilters; ++i )
539 mFilters[i]->Refresh();
543 void EffectsView::RemoveFilters()
545 const size_t numFilters( mFilters.size() );
546 for( size_t i = 0; i < numFilters; ++i )
553 } // namespace Internal
555 } // namespace Toolkit