2 // Copyright (c) 2014 Samsung Electronics Co., Ltd.
4 // Licensed under the Flora License, Version 1.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://floralicense.org/license/
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.
18 #include "effects-view-impl.h"
21 #include "../../filters/blur-two-pass-filter.h"
22 #include "../../filters/emboss-filter.h"
23 #include "../../filters/spread-filter.h"
37 Dali::BaseHandle Create()
39 return Toolkit::EffectsView::New();
42 Dali::TypeRegistration mType( typeid(Dali::Toolkit::EffectsView), typeid(Dali::Toolkit::Control), Create );
44 const Pixel::Format EFFECTS_VIEW_DEFAULT_PIXEL_FORMAT = Pixel::RGBA8888;
45 const float ARBITRARY_FIELD_OF_VIEW = Math::PI / 4.0f;
46 const Vector4 EFFECTS_VIEW_DEFAULT_BACKGROUND_COLOR( 1.0f, 1.0f, 1.0f, 0.0 );
47 const bool EFFECTS_VIEW_REFRESH_ON_DEMAND(false);
49 const float EFFECT_SIZE_DEFAULT( 1.0f );
50 const std::string EFFECT_SIZE_PROPERTY_NAME( "EffectSize" );
51 const float EFFECT_STRENGTH_DEFAULT( 0.5f );
52 const std::string EFFECT_STRENGTH_PROPERTY_NAME( "EffectStrength" );
53 const Vector3 EFFECT_OFFSET_DEFAULT( 0.0f, 0.0f, 0.0f );
54 const std::string EFFECT_OFFSET_PROPERTY_NAME( "EffectOffset" );
55 const Vector4 EFFECT_COLOR_DEFAULT( Color::WHITE );
56 const std::string EFFECT_COLOR_PROPERTY_NAME( "EffectColor" );
58 const char* const EFFECTS_VIEW_FRAGMENT_SOURCE =
61 " gl_FragColor = uColor;\n"
62 " gl_FragColor.a *= texture2D( sTexture, vTexCoord).a;\n"
65 const float BLUR_KERNEL0[] = { 12.0f/16.0f,
66 2.0f/16.0f, 2.0f/16.0f };
68 const float BLUR_KERNEL1[] = { 8.0f/16.0f,
69 4.0f/16.0f, 4.0f/16.0f };
71 const float BLUR_KERNEL2[] = { 6.0f/16.0f,
72 2.5f/16.0f, 2.5f/16.0f,
73 1.5f/16.0f, 1.5f/16.0f,
74 1.0f/16.0f, 1.0f/16.0f };
76 const float BLUR_KERNEL3[] = { 4.0f/16.0f,
77 3.0f/16.0f, 2.0f/16.0f,
78 2.0f/16.0f, 2.0f/16.0f,
79 1.0f/16.0f, 1.0f/16.0f };
81 const float BLUR_KERNEL4[] = { 3.0f/16.0f,
82 2.5f/16.0f, 2.5f/16.0f,
83 1.75f/16.0f, 1.75f/16.0f,
84 1.25f/16.0f, 1.25f/16.0f,
85 1.0f/16.0f, 1.0f/16.0f };
89 Toolkit::EffectsView EffectsView::New()
91 EffectsView* effectsView = new EffectsView;
93 Toolkit::EffectsView handle = Toolkit::EffectsView( *effectsView );
95 // Second-phase init of the implementation
96 // This can only be done after the CustomActor connection has been made...
97 effectsView->Initialize();
102 EffectsView::EffectsView()
104 mEffectType( Toolkit::EffectsView::INVALID_TYPE ),
105 mPixelFormat( EFFECTS_VIEW_DEFAULT_PIXEL_FORMAT ),
107 mBackgroundColor( EFFECTS_VIEW_DEFAULT_BACKGROUND_COLOR ),
108 mTargetSize( Vector2::ZERO ),
109 mLastSize( Vector2::ZERO ),
110 mRefreshOnDemand(EFFECTS_VIEW_REFRESH_ON_DEMAND),
111 mEffectSizePropertyIndex(Property::INVALID_INDEX),
112 mEffectStrengthPropertyIndex(Property::INVALID_INDEX),
113 mEffectOffsetPropertyIndex(Property::INVALID_INDEX),
114 mEffectColorPropertyIndex(Property::INVALID_INDEX)
118 EffectsView::~EffectsView()
123 void EffectsView::SetType( Toolkit::EffectsView::EffectType type )
125 if( mEffectType != type )
131 switch( mEffectType )
133 case Toolkit::EffectsView::DROP_SHADOW:
135 mFilters.push_back( new SpreadFilter );
136 mFilters.push_back( new BlurTwoPassFilter );
139 case Toolkit::EffectsView::EMBOSS:
141 mFilters.push_back( new SpreadFilter );
142 mFilters.push_back( new EmbossFilter );
143 mFilters.push_back( new BlurTwoPassFilter );
144 mActorPostFilter.RemoveShaderEffect();
155 Toolkit::EffectsView::EffectType EffectsView::GetType() const
160 void EffectsView::Enable()
162 // make sure resources are allocated and start the render tasks processing
167 void EffectsView::Disable()
169 // stop render tasks processing
170 // Note: render target resources are automatically freed since we set the Image::Unused flag
174 void EffectsView::Refresh()
176 RefreshRenderTasks();
179 void EffectsView::SetRefreshOnDemand( bool onDemand )
181 mRefreshOnDemand = onDemand;
183 RefreshRenderTasks();
186 void EffectsView::SetPixelFormat( Pixel::Format pixelFormat )
188 mPixelFormat = pixelFormat;
191 void EffectsView::SetOutputImage( FrameBufferImage image )
193 CustomActor self = Self();
195 if( mImageForResult != image )
199 if( mImageForResult )
201 self.Remove( mActorForResult );
202 mActorForResult.Reset();
204 self.Add( mActorPostFilter );
205 self.Add( mActorForChildren );
210 if( mImageForResult )
212 self.Remove( mActorForResult );
214 mActorForResult = Actor::New();
215 mActorForResult.SetParentOrigin( ParentOrigin::CENTER );
216 mActorForResult.ApplyConstraint( Constraint::New<Vector3>( Actor::SIZE, ParentSource( Actor::SIZE ), EqualToConstraint() ) );
217 mActorForResult.ScaleBy( Vector3(1.0f, -1.0f, 1.0f) );
219 Self().Add( mActorForResult );
220 mActorForResult.Add( mActorPostFilter );
221 mActorForResult.Add( mActorForChildren );
223 mImageForResult = image;
227 FrameBufferImage EffectsView::GetOutputImage()
229 return mImageForResult;
232 Property::Index EffectsView::GetEffectSizePropertyIndex() const
234 return mEffectSizePropertyIndex;
237 Property::Index EffectsView::GetEffectStrengthPropertyIndex() const
239 return mEffectStrengthPropertyIndex;
242 Property::Index EffectsView::GetEffectOffsetPropertyIndex() const
244 return mEffectOffsetPropertyIndex;
247 Property::Index EffectsView::GetEffectColorPropertyIndex() const
249 return mEffectColorPropertyIndex;
252 void EffectsView::SetupProperties()
254 CustomActor self = Self();
256 // Register a property that the user can control the drop shadow offset
257 mEffectSizePropertyIndex = self.RegisterProperty(EFFECT_SIZE_PROPERTY_NAME, EFFECT_SIZE_DEFAULT, Property::READ_WRITE);
258 mEffectStrengthPropertyIndex = self.RegisterProperty(EFFECT_STRENGTH_PROPERTY_NAME, EFFECT_STRENGTH_DEFAULT, Property::READ_WRITE);
259 mEffectOffsetPropertyIndex = self.RegisterProperty(EFFECT_OFFSET_PROPERTY_NAME, EFFECT_OFFSET_DEFAULT);
260 mEffectColorPropertyIndex = self.RegisterProperty(EFFECT_COLOR_PROPERTY_NAME, EFFECT_COLOR_DEFAULT);
261 mActorPostFilter.ApplyConstraint( Constraint::New<Vector3>( Actor::POSITION, Source( self, mEffectOffsetPropertyIndex ), EqualToConstraint() ) );
262 mActorPostFilter.ApplyConstraint( Constraint::New<Vector3>( Actor::SIZE, ParentSource( Actor::SIZE ), EqualToConstraint() ) );
263 mActorPostFilter.ApplyConstraint( Constraint::New<Vector4>( Actor::COLOR, Source( self, mEffectColorPropertyIndex ), EqualToConstraint() ) );
266 void EffectsView::SetBackgroundColor( const Vector4& color )
268 mBackgroundColor = color;
271 Vector4 EffectsView::GetBackgroundColor() const
273 return mBackgroundColor;
277 void EffectsView::OnInitialize()
279 //////////////////////////////////////////////////////
281 mCameraForChildren = CameraActor::New();
282 mCameraForChildren.SetParentOrigin(ParentOrigin::CENTER);
284 mActorForChildren = ImageActor::New();
285 mActorForChildren.SetPositionInheritanceMode( Dali::USE_PARENT_POSITION );
286 mActorForChildren.ApplyConstraint( Constraint::New<Vector3>( Actor::SIZE, ParentSource( Actor::SIZE ), EqualToConstraint() ) ); // same size as EffectsView object
287 mActorForChildren.ScaleBy( Vector3(1.0f, -1.0f, 1.0f) );
289 mActorPostFilter = ImageActor::New();
290 mActorPostFilter.SetParentOrigin( ParentOrigin::CENTER );
291 mActorPostFilter.ApplyConstraint( Constraint::New<Vector3>( Actor::SIZE, ParentSource( Actor::SIZE ), EqualToConstraint() ) ); // same size as EffectsView object
292 mActorPostFilter.ScaleBy( Vector3(1.0f, -1.0f, 1.0f) );
293 mActorPostFilter.SetShaderEffect( ShaderEffect::New( "", EFFECTS_VIEW_FRAGMENT_SOURCE ) );
295 // Connect to actor tree
296 Self().Add( mActorPostFilter );
297 Self().Add( mActorForChildren );
298 Self().Add( mCameraForChildren );
303 void EffectsView::OnControlSizeSet(const Vector3& targetSize)
305 mTargetSize = Vector2(targetSize);
307 // if we are already on stage, need to update render target sizes now to reflect the new size of this actor
314 void EffectsView::OnStageDisconnection()
316 const size_t numFilters( mFilters.size() );
317 for( size_t i = 0; i < numFilters; ++i )
319 mFilters[i]->Disable();
323 void EffectsView::SetupFilters()
325 int effectSize = static_cast< int >( Self().GetProperty( mEffectSizePropertyIndex ).Get<float>() );
326 switch( mEffectType )
328 case Toolkit::EffectsView::DROP_SHADOW:
330 SpreadFilter* spreadFilter = static_cast< SpreadFilter* >( mFilters[0] );
331 spreadFilter->SetInputImage( mImageForChildren );
332 spreadFilter->SetOutputImage( mImagePostFilter );
333 spreadFilter->SetRootActor( Self() );
334 spreadFilter->SetBackgroundColor( mBackgroundColor );
335 spreadFilter->SetPixelFormat( mPixelFormat );
336 spreadFilter->SetSize( mTargetSize );
337 spreadFilter->SetSpread( effectSize );
339 BlurTwoPassFilter* blurFilter = static_cast< BlurTwoPassFilter* >( mFilters[1] );
340 blurFilter->SetInputImage( mImagePostFilter );
341 blurFilter->SetOutputImage( mImagePostFilter );
342 blurFilter->SetRootActor( Self() );
343 blurFilter->SetBackgroundColor( mBackgroundColor );
344 blurFilter->SetPixelFormat( mPixelFormat );
345 blurFilter->SetSize( mTargetSize );
347 const float* kernel(NULL);
348 size_t kernelSize(0);
351 case 4: { kernel = BLUR_KERNEL4; kernelSize = sizeof(BLUR_KERNEL4)/sizeof(BLUR_KERNEL4[0]); break; }
352 case 3: { kernel = BLUR_KERNEL3; kernelSize = sizeof(BLUR_KERNEL3)/sizeof(BLUR_KERNEL3[0]); break; }
353 case 2: { kernel = BLUR_KERNEL2; kernelSize = sizeof(BLUR_KERNEL2)/sizeof(BLUR_KERNEL2[0]); break; }
354 case 1: { kernel = BLUR_KERNEL1; kernelSize = sizeof(BLUR_KERNEL1)/sizeof(BLUR_KERNEL1[0]); break; }
356 default: { kernel = BLUR_KERNEL0; kernelSize = sizeof(BLUR_KERNEL0)/sizeof(BLUR_KERNEL0[0]); break; }
358 blurFilter->CreateKernel( kernel, kernelSize );
361 case Toolkit::EffectsView::EMBOSS:
363 SpreadFilter* spreadFilter = static_cast< SpreadFilter* >( mFilters[0] );
364 spreadFilter->SetInputImage( mImageForChildren );
365 spreadFilter->SetOutputImage( mImagePostFilter );
366 spreadFilter->SetRootActor( Self() );
367 spreadFilter->SetBackgroundColor( mBackgroundColor );
368 spreadFilter->SetPixelFormat( Pixel::RGBA8888 );
369 spreadFilter->SetSize( mTargetSize );
370 spreadFilter->SetSpread( effectSize );
372 EmbossFilter* embossFilter = static_cast< EmbossFilter* >( mFilters[1] );
373 embossFilter->SetInputImage( mImagePostFilter );
374 embossFilter->SetOutputImage( mImagePostFilter );
375 embossFilter->SetRootActor( Self() );
376 embossFilter->SetBackgroundColor( mBackgroundColor );
377 embossFilter->SetPixelFormat( Pixel::RGBA8888 );
378 embossFilter->SetSize( mTargetSize );
380 BlurTwoPassFilter* blurFilter = static_cast< BlurTwoPassFilter* >( mFilters[2] );
381 blurFilter->SetInputImage( mImagePostFilter );
382 blurFilter->SetOutputImage( mImagePostFilter );
383 blurFilter->SetRootActor( Self() );
384 blurFilter->SetBackgroundColor( Vector4( 0.5f, 0.5f, 0.5f, 0.0 ) );
385 blurFilter->SetPixelFormat( Pixel::RGBA8888 );
386 blurFilter->SetSize( mTargetSize );
387 blurFilter->CreateKernel( BLUR_KERNEL0, sizeof(BLUR_KERNEL0)/sizeof(BLUR_KERNEL0[0]) );
397 void EffectsView::AllocateResources()
399 if(mTargetSize != mLastSize)
401 mLastSize = mTargetSize;
405 mImageForChildren = FrameBufferImage::New( mTargetSize.width, mTargetSize.height, mPixelFormat, Dali::Image::Unused );
406 mActorForChildren.SetImage(mImageForChildren);
408 mImagePostFilter = FrameBufferImage::New( mTargetSize.width, mTargetSize.height, mPixelFormat, Dali::Image::Unused );
409 mActorPostFilter.SetImage(mImagePostFilter);
415 void EffectsView::SetupCameras()
417 const float cameraPosConstraintScale( 0.5f / tanf(ARBITRARY_FIELD_OF_VIEW * 0.5f) );
419 // Create and place a camera for the children render, corresponding to its render target size
420 mCameraForChildren.SetFieldOfView(ARBITRARY_FIELD_OF_VIEW);
421 // 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
422 mCameraForChildren.SetNearClippingPlane(1.0f);
423 mCameraForChildren.SetAspectRatio(mTargetSize.width / mTargetSize.height);
424 mCameraForChildren.SetType(Dali::Camera::FREE_LOOK); // camera orientation based solely on actor
425 mCameraForChildren.SetPosition(0.0f, 0.0f, mTargetSize.height * cameraPosConstraintScale);
426 mCameraForChildren.SetRotation(Quaternion(M_PI, Vector3::YAXIS));
428 // Children render camera must move when EffectsView object is resized.
429 // This is since we cannot change render target size - so we need to remap the child actors' rendering
430 // accordingly so they still exactly fill the render target.
431 // Note that this means the effective resolution of the child render changes as the EffectsView object
432 // changes size, this is the trade off for not being able to modify render target size
433 // Change camera z position based on EffectsView actor height
434 mCameraForChildren.RemoveConstraints();
435 mCameraForChildren.ApplyConstraint( Constraint::New<float>( Actor::POSITION_Z, ParentSource( Actor::SIZE_HEIGHT ), RelativeToConstraintFloat(cameraPosConstraintScale) ) );
438 void EffectsView::CreateRenderTasks()
440 RenderTaskList taskList = Stage::GetCurrent().GetRenderTaskList();
442 // create render task to render our child actors to offscreen buffer
443 mRenderTaskForChildren = taskList.CreateTask();
444 mRenderTaskForChildren.SetRefreshRate( mRefreshOnDemand ? RenderTask::REFRESH_ONCE : RenderTask::REFRESH_ALWAYS );
445 mRenderTaskForChildren.SetSourceActor( Self() );
446 mRenderTaskForChildren.SetExclusive(true);
447 mRenderTaskForChildren.SetInputEnabled( false );
448 mRenderTaskForChildren.SetClearColor( mBackgroundColor );
449 mRenderTaskForChildren.SetClearEnabled( true );
450 mRenderTaskForChildren.SetTargetFrameBuffer( mImageForChildren );
451 mRenderTaskForChildren.SetCameraActor(mCameraForChildren); // use camera that covers render target exactly
453 // Enable image filters
454 const size_t numFilters( mFilters.size() );
455 for( size_t i = 0; i < numFilters; ++i )
457 mFilters[i]->Enable();
460 // create render task to render result of the image filters to the final offscreen
461 if( mImageForResult )
463 mRenderTaskForResult = taskList.CreateTask();
464 mRenderTaskForResult.SetRefreshRate( mRefreshOnDemand ? RenderTask::REFRESH_ONCE : RenderTask::REFRESH_ALWAYS );
465 mRenderTaskForResult.SetSourceActor( mActorForResult );
466 mRenderTaskForResult.SetExclusive(true);
467 mRenderTaskForResult.SetInputEnabled( false );
468 mRenderTaskForResult.SetClearColor( mBackgroundColor );
469 mRenderTaskForResult.SetClearEnabled( true );
470 mRenderTaskForResult.SetTargetFrameBuffer( mImageForResult );
471 mRenderTaskForResult.SetCameraActor(mCameraForChildren); // use camera that covers render target exactly
475 void EffectsView::RemoveRenderTasks()
477 RenderTaskList taskList = Stage::GetCurrent().GetRenderTaskList();
479 taskList.RemoveTask(mRenderTaskForChildren);
480 taskList.RemoveTask(mRenderTaskForResult);
482 const size_t numFilters( mFilters.size() );
483 for( size_t i = 0; i < numFilters; ++i )
485 mFilters[i]->Disable();
489 void EffectsView::RefreshRenderTasks()
491 RenderTaskList taskList = Stage::GetCurrent().GetRenderTaskList();
493 if( mRenderTaskForChildren )
495 mRenderTaskForChildren.SetRefreshRate( mRefreshOnDemand ? RenderTask::REFRESH_ONCE : RenderTask::REFRESH_ALWAYS );
498 if( mRenderTaskForResult )
500 mRenderTaskForResult.SetRefreshRate( mRefreshOnDemand ? RenderTask::REFRESH_ONCE : RenderTask::REFRESH_ALWAYS );
503 const size_t numFilters( mFilters.size() );
504 for( size_t i = 0; i < numFilters; ++i )
506 mFilters[i]->Refresh();
510 void EffectsView::RemoveFilters()
512 const size_t numFilters( mFilters.size() );
513 for( size_t i = 0; i < numFilters; ++i )
520 } // namespace Internal
522 } // namespace Toolkit