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/render-tasks/render-task-list.h>
30 #include "../../filters/blur-two-pass-filter.h"
31 #include "../../filters/emboss-filter.h"
32 #include "../../filters/spread-filter.h"
46 Dali::BaseHandle Create()
48 return Toolkit::EffectsView::New();
51 Dali::TypeRegistration mType( typeid(Dali::Toolkit::EffectsView), typeid(Dali::Toolkit::Control), Create );
53 const Pixel::Format EFFECTS_VIEW_DEFAULT_PIXEL_FORMAT = Pixel::RGBA8888;
54 const float ARBITRARY_FIELD_OF_VIEW = Math::PI / 4.0f;
55 const Vector4 EFFECTS_VIEW_DEFAULT_BACKGROUND_COLOR( 1.0f, 1.0f, 1.0f, 0.0 );
56 const bool EFFECTS_VIEW_REFRESH_ON_DEMAND(false);
58 const float EFFECT_SIZE_DEFAULT( 1.0f );
59 const std::string EFFECT_SIZE_PROPERTY_NAME( "EffectSize" );
60 const float EFFECT_STRENGTH_DEFAULT( 0.5f );
61 const std::string EFFECT_STRENGTH_PROPERTY_NAME( "EffectStrength" );
62 const Vector3 EFFECT_OFFSET_DEFAULT( 0.0f, 0.0f, 0.0f );
63 const std::string EFFECT_OFFSET_PROPERTY_NAME( "EffectOffset" );
64 const Vector4 EFFECT_COLOR_DEFAULT( Color::WHITE );
65 const std::string EFFECT_COLOR_PROPERTY_NAME( "EffectColor" );
67 const char* const EFFECTS_VIEW_FRAGMENT_SOURCE =
70 " gl_FragColor = uColor;\n"
71 " gl_FragColor.a *= texture2D( sTexture, vTexCoord).a;\n"
74 const float BLUR_KERNEL0[] = { 12.0f/16.0f,
75 2.0f/16.0f, 2.0f/16.0f };
77 const float BLUR_KERNEL1[] = { 8.0f/16.0f,
78 4.0f/16.0f, 4.0f/16.0f };
80 const float BLUR_KERNEL2[] = { 6.0f/16.0f,
81 2.5f/16.0f, 2.5f/16.0f,
82 1.5f/16.0f, 1.5f/16.0f,
83 1.0f/16.0f, 1.0f/16.0f };
85 const float BLUR_KERNEL3[] = { 4.0f/16.0f,
86 3.0f/16.0f, 2.0f/16.0f,
87 2.0f/16.0f, 2.0f/16.0f,
88 1.0f/16.0f, 1.0f/16.0f };
90 const float BLUR_KERNEL4[] = { 3.0f/16.0f,
91 2.5f/16.0f, 2.5f/16.0f,
92 1.75f/16.0f, 1.75f/16.0f,
93 1.25f/16.0f, 1.25f/16.0f,
94 1.0f/16.0f, 1.0f/16.0f };
98 Toolkit::EffectsView EffectsView::New()
100 EffectsView* effectsView = new EffectsView;
102 Toolkit::EffectsView handle = Toolkit::EffectsView( *effectsView );
104 // Second-phase init of the implementation
105 // This can only be done after the CustomActor connection has been made...
106 effectsView->Initialize();
111 EffectsView::EffectsView()
112 : Control( CONTROL_BEHAVIOUR_NONE ),
113 mEffectType( Toolkit::EffectsView::INVALID_TYPE ),
114 mPixelFormat( EFFECTS_VIEW_DEFAULT_PIXEL_FORMAT ),
116 mBackgroundColor( EFFECTS_VIEW_DEFAULT_BACKGROUND_COLOR ),
117 mTargetSize( Vector2::ZERO ),
118 mLastSize( Vector2::ZERO ),
119 mRefreshOnDemand(EFFECTS_VIEW_REFRESH_ON_DEMAND),
120 mEffectSizePropertyIndex(Property::INVALID_INDEX),
121 mEffectStrengthPropertyIndex(Property::INVALID_INDEX),
122 mEffectOffsetPropertyIndex(Property::INVALID_INDEX),
123 mEffectColorPropertyIndex(Property::INVALID_INDEX)
127 EffectsView::~EffectsView()
132 void EffectsView::SetType( Toolkit::EffectsView::EffectType type )
134 if( mEffectType != type )
140 switch( mEffectType )
142 case Toolkit::EffectsView::DROP_SHADOW:
144 mFilters.push_back( new SpreadFilter );
145 mFilters.push_back( new BlurTwoPassFilter );
148 case Toolkit::EffectsView::EMBOSS:
150 mFilters.push_back( new SpreadFilter );
151 mFilters.push_back( new EmbossFilter );
152 mFilters.push_back( new BlurTwoPassFilter );
153 mActorPostFilter.RemoveShaderEffect();
164 Toolkit::EffectsView::EffectType EffectsView::GetType() const
169 void EffectsView::Enable()
171 // make sure resources are allocated and start the render tasks processing
176 void EffectsView::Disable()
178 // stop render tasks processing
179 // Note: render target resources are automatically freed since we set the Image::Unused flag
183 void EffectsView::Refresh()
185 RefreshRenderTasks();
188 void EffectsView::SetRefreshOnDemand( bool onDemand )
190 mRefreshOnDemand = onDemand;
192 RefreshRenderTasks();
195 void EffectsView::SetPixelFormat( Pixel::Format pixelFormat )
197 mPixelFormat = pixelFormat;
200 void EffectsView::SetOutputImage( FrameBufferImage image )
202 CustomActor self = Self();
204 if( mImageForResult != image )
208 if( mImageForResult )
210 self.Remove( mActorForResult );
211 mActorForResult.Reset();
213 self.Add( mActorPostFilter );
214 self.Add( mActorForChildren );
219 if( mImageForResult )
221 self.Remove( mActorForResult );
223 mActorForResult = Actor::New();
224 mActorForResult.SetParentOrigin( ParentOrigin::CENTER );
225 mActorForResult.SetSize( mTargetSize );
226 mActorForResult.ScaleBy( Vector3(1.0f, -1.0f, 1.0f) );
228 Self().Add( mActorForResult );
229 mActorForResult.Add( mActorPostFilter );
230 mActorForResult.Add( mActorForChildren );
232 mImageForResult = image;
236 FrameBufferImage EffectsView::GetOutputImage()
238 return mImageForResult;
241 Property::Index EffectsView::GetEffectSizePropertyIndex() const
243 return mEffectSizePropertyIndex;
246 Property::Index EffectsView::GetEffectStrengthPropertyIndex() const
248 return mEffectStrengthPropertyIndex;
251 Property::Index EffectsView::GetEffectOffsetPropertyIndex() const
253 return mEffectOffsetPropertyIndex;
256 Property::Index EffectsView::GetEffectColorPropertyIndex() const
258 return mEffectColorPropertyIndex;
261 void EffectsView::SetupProperties()
263 CustomActor self = Self();
265 // Register a property that the user can control the drop shadow offset
266 mEffectSizePropertyIndex = self.RegisterProperty(EFFECT_SIZE_PROPERTY_NAME, EFFECT_SIZE_DEFAULT, Property::READ_WRITE);
267 mEffectStrengthPropertyIndex = self.RegisterProperty(EFFECT_STRENGTH_PROPERTY_NAME, EFFECT_STRENGTH_DEFAULT, Property::READ_WRITE);
268 mEffectOffsetPropertyIndex = self.RegisterProperty(EFFECT_OFFSET_PROPERTY_NAME, EFFECT_OFFSET_DEFAULT);
269 mEffectColorPropertyIndex = self.RegisterProperty(EFFECT_COLOR_PROPERTY_NAME, EFFECT_COLOR_DEFAULT);
270 mActorPostFilter.ApplyConstraint( Constraint::New<Vector3>( Actor::Property::POSITION, Source( self, mEffectOffsetPropertyIndex ), EqualToConstraint() ) );
271 mActorPostFilter.ApplyConstraint( Constraint::New<Vector4>( Actor::Property::COLOR, Source( self, mEffectColorPropertyIndex ), EqualToConstraint() ) );
274 void EffectsView::SetBackgroundColor( const Vector4& color )
276 mBackgroundColor = color;
279 Vector4 EffectsView::GetBackgroundColor() const
281 return mBackgroundColor;
285 void EffectsView::OnInitialize()
287 //////////////////////////////////////////////////////
289 mCameraForChildren = CameraActor::New();
290 mCameraForChildren.SetParentOrigin(ParentOrigin::CENTER);
292 mActorForChildren = ImageActor::New();
293 mActorForChildren.SetPositionInheritanceMode( Dali::USE_PARENT_POSITION );
294 mActorForChildren.ScaleBy( Vector3(1.0f, -1.0f, 1.0f) );
296 mActorPostFilter = ImageActor::New();
297 mActorPostFilter.SetParentOrigin( ParentOrigin::CENTER );
298 mActorPostFilter.ScaleBy( Vector3(1.0f, -1.0f, 1.0f) );
299 mActorPostFilter.SetShaderEffect( ShaderEffect::New( "", EFFECTS_VIEW_FRAGMENT_SOURCE ) );
301 // Connect to actor tree
302 Self().Add( mActorPostFilter );
303 Self().Add( mActorForChildren );
304 Self().Add( mCameraForChildren );
309 void EffectsView::OnControlSizeSet(const Vector3& targetSize)
311 mTargetSize = Vector2(targetSize);
313 // if we are already on stage, need to update render target sizes now to reflect the new size of this actor
319 if( mActorForResult )
321 mActorForResult.SetSize( targetSize );
323 if( mActorForChildren )
325 mActorForChildren.SetSize( targetSize );
327 if( mActorPostFilter )
329 mActorPostFilter.SetSize( targetSize );
332 // Children render camera must move when EffectsView object is resized.
333 // This is since we cannot change render target size - so we need to remap the child actors' rendering
334 // accordingly so they still exactly fill the render target.
335 // Note that this means the effective resolution of the child render changes as the EffectsView object
336 // changes size, this is the trade off for not being able to modify render target size
337 // Change camera z position based on EffectsView actor height
338 if( mCameraForChildren )
340 const float cameraPosScale( 0.5f / tanf(ARBITRARY_FIELD_OF_VIEW * 0.5f) );
341 mCameraForChildren.SetZ( targetSize.height * cameraPosScale );
344 const size_t numFilters( mFilters.size() );
345 for( size_t i = 0; i < numFilters; ++i )
347 mFilters[i]->SetSize( mTargetSize );
352 void EffectsView::OnStageDisconnection()
354 const size_t numFilters( mFilters.size() );
355 for( size_t i = 0; i < numFilters; ++i )
357 mFilters[i]->Disable();
361 void EffectsView::SetupFilters()
363 int effectSize = static_cast< int >( Self().GetProperty( mEffectSizePropertyIndex ).Get<float>() );
364 switch( mEffectType )
366 case Toolkit::EffectsView::DROP_SHADOW:
368 SpreadFilter* spreadFilter = static_cast< SpreadFilter* >( mFilters[0] );
369 spreadFilter->SetInputImage( mImageForChildren );
370 spreadFilter->SetOutputImage( mImagePostFilter );
371 spreadFilter->SetRootActor( Self() );
372 spreadFilter->SetBackgroundColor( mBackgroundColor );
373 spreadFilter->SetPixelFormat( mPixelFormat );
374 spreadFilter->SetSize( mTargetSize );
375 spreadFilter->SetSpread( effectSize );
377 BlurTwoPassFilter* blurFilter = static_cast< BlurTwoPassFilter* >( mFilters[1] );
378 blurFilter->SetInputImage( mImagePostFilter );
379 blurFilter->SetOutputImage( mImagePostFilter );
380 blurFilter->SetRootActor( Self() );
381 blurFilter->SetBackgroundColor( mBackgroundColor );
382 blurFilter->SetPixelFormat( mPixelFormat );
383 blurFilter->SetSize( mTargetSize );
385 const float* kernel(NULL);
386 size_t kernelSize(0);
389 case 4: { kernel = BLUR_KERNEL4; kernelSize = sizeof(BLUR_KERNEL4)/sizeof(BLUR_KERNEL4[0]); break; }
390 case 3: { kernel = BLUR_KERNEL3; kernelSize = sizeof(BLUR_KERNEL3)/sizeof(BLUR_KERNEL3[0]); break; }
391 case 2: { kernel = BLUR_KERNEL2; kernelSize = sizeof(BLUR_KERNEL2)/sizeof(BLUR_KERNEL2[0]); break; }
392 case 1: { kernel = BLUR_KERNEL1; kernelSize = sizeof(BLUR_KERNEL1)/sizeof(BLUR_KERNEL1[0]); break; }
394 default: { kernel = BLUR_KERNEL0; kernelSize = sizeof(BLUR_KERNEL0)/sizeof(BLUR_KERNEL0[0]); break; }
396 blurFilter->CreateKernel( kernel, kernelSize );
399 case Toolkit::EffectsView::EMBOSS:
401 SpreadFilter* spreadFilter = static_cast< SpreadFilter* >( mFilters[0] );
402 spreadFilter->SetInputImage( mImageForChildren );
403 spreadFilter->SetOutputImage( mImagePostFilter );
404 spreadFilter->SetRootActor( Self() );
405 spreadFilter->SetBackgroundColor( mBackgroundColor );
406 spreadFilter->SetPixelFormat( Pixel::RGBA8888 );
407 spreadFilter->SetSize( mTargetSize );
408 spreadFilter->SetSpread( effectSize );
410 EmbossFilter* embossFilter = static_cast< EmbossFilter* >( mFilters[1] );
411 embossFilter->SetInputImage( mImagePostFilter );
412 embossFilter->SetOutputImage( mImagePostFilter );
413 embossFilter->SetRootActor( Self() );
414 embossFilter->SetBackgroundColor( mBackgroundColor );
415 embossFilter->SetPixelFormat( Pixel::RGBA8888 );
416 embossFilter->SetSize( mTargetSize );
418 BlurTwoPassFilter* blurFilter = static_cast< BlurTwoPassFilter* >( mFilters[2] );
419 blurFilter->SetInputImage( mImagePostFilter );
420 blurFilter->SetOutputImage( mImagePostFilter );
421 blurFilter->SetRootActor( Self() );
422 blurFilter->SetBackgroundColor( Vector4( 0.5f, 0.5f, 0.5f, 0.0 ) );
423 blurFilter->SetPixelFormat( Pixel::RGBA8888 );
424 blurFilter->SetSize( mTargetSize );
425 blurFilter->CreateKernel( BLUR_KERNEL0, sizeof(BLUR_KERNEL0)/sizeof(BLUR_KERNEL0[0]) );
435 void EffectsView::AllocateResources()
437 if(mTargetSize != mLastSize)
439 mLastSize = mTargetSize;
443 mImageForChildren = FrameBufferImage::New( mTargetSize.width, mTargetSize.height, mPixelFormat, Dali::Image::UNUSED );
444 mActorForChildren.SetImage(mImageForChildren);
446 mImagePostFilter = FrameBufferImage::New( mTargetSize.width, mTargetSize.height, mPixelFormat, Dali::Image::UNUSED );
447 mActorPostFilter.SetImage(mImagePostFilter);
453 void EffectsView::SetupCameras()
455 const float cameraPosScale( 0.5f / tanf(ARBITRARY_FIELD_OF_VIEW * 0.5f) );
457 // Create and place a camera for the children render, corresponding to its render target size
458 mCameraForChildren.SetFieldOfView(ARBITRARY_FIELD_OF_VIEW);
459 // 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
460 mCameraForChildren.SetNearClippingPlane(1.0f);
461 mCameraForChildren.SetAspectRatio(mTargetSize.width / mTargetSize.height);
462 mCameraForChildren.SetType(Dali::Camera::FREE_LOOK); // camera orientation based solely on actor
463 mCameraForChildren.SetPosition(0.0f, 0.0f, mTargetSize.height * cameraPosScale);
464 mCameraForChildren.SetRotation(Quaternion(M_PI, Vector3::YAXIS));
465 mCameraForChildren.SetZ( mTargetSize.height * cameraPosScale );
468 void EffectsView::CreateRenderTasks()
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( Self() );
476 mRenderTaskForChildren.SetExclusive(true);
477 mRenderTaskForChildren.SetInputEnabled( false );
478 mRenderTaskForChildren.SetClearColor( mBackgroundColor );
479 mRenderTaskForChildren.SetClearEnabled( true );
480 mRenderTaskForChildren.SetTargetFrameBuffer( mImageForChildren );
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();
490 // create render task to render result of the image filters to the final offscreen
491 if( mImageForResult )
493 mRenderTaskForResult = taskList.CreateTask();
494 mRenderTaskForResult.SetRefreshRate( mRefreshOnDemand ? RenderTask::REFRESH_ONCE : RenderTask::REFRESH_ALWAYS );
495 mRenderTaskForResult.SetSourceActor( mActorForResult );
496 mRenderTaskForResult.SetExclusive(true);
497 mRenderTaskForResult.SetInputEnabled( false );
498 mRenderTaskForResult.SetClearColor( mBackgroundColor );
499 mRenderTaskForResult.SetClearEnabled( true );
500 mRenderTaskForResult.SetTargetFrameBuffer( mImageForResult );
501 mRenderTaskForResult.SetCameraActor(mCameraForChildren); // use camera that covers render target exactly
505 void EffectsView::RemoveRenderTasks()
507 RenderTaskList taskList = Stage::GetCurrent().GetRenderTaskList();
509 taskList.RemoveTask(mRenderTaskForChildren);
510 taskList.RemoveTask(mRenderTaskForResult);
512 const size_t numFilters( mFilters.size() );
513 for( size_t i = 0; i < numFilters; ++i )
515 mFilters[i]->Disable();
519 void EffectsView::RefreshRenderTasks()
521 RenderTaskList taskList = Stage::GetCurrent().GetRenderTaskList();
523 if( mRenderTaskForChildren )
525 mRenderTaskForChildren.SetRefreshRate( mRefreshOnDemand ? RenderTask::REFRESH_ONCE : RenderTask::REFRESH_ALWAYS );
528 if( mRenderTaskForResult )
530 mRenderTaskForResult.SetRefreshRate( mRefreshOnDemand ? RenderTask::REFRESH_ONCE : RenderTask::REFRESH_ALWAYS );
533 const size_t numFilters( mFilters.size() );
534 for( size_t i = 0; i < numFilters; ++i )
536 mFilters[i]->Refresh();
540 void EffectsView::RemoveFilters()
542 const size_t numFilters( mFilters.size() );
543 for( size_t i = 0; i < numFilters; ++i )
550 } // namespace Internal
552 } // namespace Toolkit