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/constraints.h>
23 #include <dali/public-api/common/stage.h>
24 #include <dali/public-api/object/type-registry.h>
25 #include <dali/public-api/render-tasks/render-task-list.h>
28 #include "../../filters/blur-two-pass-filter.h"
29 #include "../../filters/emboss-filter.h"
30 #include "../../filters/spread-filter.h"
44 Dali::BaseHandle Create()
46 return Toolkit::EffectsView::New();
49 Dali::TypeRegistration mType( typeid(Dali::Toolkit::EffectsView), typeid(Dali::Toolkit::Control), Create );
51 const Pixel::Format EFFECTS_VIEW_DEFAULT_PIXEL_FORMAT = Pixel::RGBA8888;
52 const float ARBITRARY_FIELD_OF_VIEW = Math::PI / 4.0f;
53 const Vector4 EFFECTS_VIEW_DEFAULT_BACKGROUND_COLOR( 1.0f, 1.0f, 1.0f, 0.0 );
54 const bool EFFECTS_VIEW_REFRESH_ON_DEMAND(false);
56 const float EFFECT_SIZE_DEFAULT( 1.0f );
57 const std::string EFFECT_SIZE_PROPERTY_NAME( "EffectSize" );
58 const float EFFECT_STRENGTH_DEFAULT( 0.5f );
59 const std::string EFFECT_STRENGTH_PROPERTY_NAME( "EffectStrength" );
60 const Vector3 EFFECT_OFFSET_DEFAULT( 0.0f, 0.0f, 0.0f );
61 const std::string EFFECT_OFFSET_PROPERTY_NAME( "EffectOffset" );
62 const Vector4 EFFECT_COLOR_DEFAULT( Color::WHITE );
63 const std::string EFFECT_COLOR_PROPERTY_NAME( "EffectColor" );
65 const char* const EFFECTS_VIEW_FRAGMENT_SOURCE =
68 " gl_FragColor = uColor;\n"
69 " gl_FragColor.a *= texture2D( sTexture, vTexCoord).a;\n"
72 const float BLUR_KERNEL0[] = { 12.0f/16.0f,
73 2.0f/16.0f, 2.0f/16.0f };
75 const float BLUR_KERNEL1[] = { 8.0f/16.0f,
76 4.0f/16.0f, 4.0f/16.0f };
78 const float BLUR_KERNEL2[] = { 6.0f/16.0f,
79 2.5f/16.0f, 2.5f/16.0f,
80 1.5f/16.0f, 1.5f/16.0f,
81 1.0f/16.0f, 1.0f/16.0f };
83 const float BLUR_KERNEL3[] = { 4.0f/16.0f,
84 3.0f/16.0f, 2.0f/16.0f,
85 2.0f/16.0f, 2.0f/16.0f,
86 1.0f/16.0f, 1.0f/16.0f };
88 const float BLUR_KERNEL4[] = { 3.0f/16.0f,
89 2.5f/16.0f, 2.5f/16.0f,
90 1.75f/16.0f, 1.75f/16.0f,
91 1.25f/16.0f, 1.25f/16.0f,
92 1.0f/16.0f, 1.0f/16.0f };
96 Toolkit::EffectsView EffectsView::New()
98 EffectsView* effectsView = new EffectsView;
100 Toolkit::EffectsView handle = Toolkit::EffectsView( *effectsView );
102 // Second-phase init of the implementation
103 // This can only be done after the CustomActor connection has been made...
104 effectsView->Initialize();
109 EffectsView::EffectsView()
110 : Control( CONTROL_BEHAVIOUR_NONE ),
111 mEffectType( Toolkit::EffectsView::INVALID_TYPE ),
112 mPixelFormat( EFFECTS_VIEW_DEFAULT_PIXEL_FORMAT ),
114 mBackgroundColor( EFFECTS_VIEW_DEFAULT_BACKGROUND_COLOR ),
115 mTargetSize( Vector2::ZERO ),
116 mLastSize( Vector2::ZERO ),
117 mRefreshOnDemand(EFFECTS_VIEW_REFRESH_ON_DEMAND),
118 mEffectSizePropertyIndex(Property::INVALID_INDEX),
119 mEffectStrengthPropertyIndex(Property::INVALID_INDEX),
120 mEffectOffsetPropertyIndex(Property::INVALID_INDEX),
121 mEffectColorPropertyIndex(Property::INVALID_INDEX)
125 EffectsView::~EffectsView()
130 void EffectsView::SetType( Toolkit::EffectsView::EffectType type )
132 if( mEffectType != type )
138 switch( mEffectType )
140 case Toolkit::EffectsView::DROP_SHADOW:
142 mFilters.push_back( new SpreadFilter );
143 mFilters.push_back( new BlurTwoPassFilter );
146 case Toolkit::EffectsView::EMBOSS:
148 mFilters.push_back( new SpreadFilter );
149 mFilters.push_back( new EmbossFilter );
150 mFilters.push_back( new BlurTwoPassFilter );
151 mActorPostFilter.RemoveShaderEffect();
162 Toolkit::EffectsView::EffectType EffectsView::GetType() const
167 void EffectsView::Enable()
169 // make sure resources are allocated and start the render tasks processing
174 void EffectsView::Disable()
176 // stop render tasks processing
177 // Note: render target resources are automatically freed since we set the Image::Unused flag
181 void EffectsView::Refresh()
183 RefreshRenderTasks();
186 void EffectsView::SetRefreshOnDemand( bool onDemand )
188 mRefreshOnDemand = onDemand;
190 RefreshRenderTasks();
193 void EffectsView::SetPixelFormat( Pixel::Format pixelFormat )
195 mPixelFormat = pixelFormat;
198 void EffectsView::SetOutputImage( FrameBufferImage image )
200 CustomActor self = Self();
202 if( mImageForResult != image )
206 if( mImageForResult )
208 self.Remove( mActorForResult );
209 mActorForResult.Reset();
211 self.Add( mActorPostFilter );
212 self.Add( mActorForChildren );
217 if( mImageForResult )
219 self.Remove( mActorForResult );
221 mActorForResult = Actor::New();
222 mActorForResult.SetParentOrigin( ParentOrigin::CENTER );
223 mActorForResult.ApplyConstraint( Constraint::New<Vector3>( Actor::SIZE, ParentSource( Actor::SIZE ), EqualToConstraint() ) );
224 mActorForResult.ScaleBy( Vector3(1.0f, -1.0f, 1.0f) );
226 Self().Add( mActorForResult );
227 mActorForResult.Add( mActorPostFilter );
228 mActorForResult.Add( mActorForChildren );
230 mImageForResult = image;
234 FrameBufferImage EffectsView::GetOutputImage()
236 return mImageForResult;
239 Property::Index EffectsView::GetEffectSizePropertyIndex() const
241 return mEffectSizePropertyIndex;
244 Property::Index EffectsView::GetEffectStrengthPropertyIndex() const
246 return mEffectStrengthPropertyIndex;
249 Property::Index EffectsView::GetEffectOffsetPropertyIndex() const
251 return mEffectOffsetPropertyIndex;
254 Property::Index EffectsView::GetEffectColorPropertyIndex() const
256 return mEffectColorPropertyIndex;
259 void EffectsView::SetupProperties()
261 CustomActor self = Self();
263 // Register a property that the user can control the drop shadow offset
264 mEffectSizePropertyIndex = self.RegisterProperty(EFFECT_SIZE_PROPERTY_NAME, EFFECT_SIZE_DEFAULT, Property::READ_WRITE);
265 mEffectStrengthPropertyIndex = self.RegisterProperty(EFFECT_STRENGTH_PROPERTY_NAME, EFFECT_STRENGTH_DEFAULT, Property::READ_WRITE);
266 mEffectOffsetPropertyIndex = self.RegisterProperty(EFFECT_OFFSET_PROPERTY_NAME, EFFECT_OFFSET_DEFAULT);
267 mEffectColorPropertyIndex = self.RegisterProperty(EFFECT_COLOR_PROPERTY_NAME, EFFECT_COLOR_DEFAULT);
268 mActorPostFilter.ApplyConstraint( Constraint::New<Vector3>( Actor::POSITION, Source( self, mEffectOffsetPropertyIndex ), EqualToConstraint() ) );
269 mActorPostFilter.ApplyConstraint( Constraint::New<Vector3>( Actor::SIZE, ParentSource( Actor::SIZE ), EqualToConstraint() ) );
270 mActorPostFilter.ApplyConstraint( Constraint::New<Vector4>( Actor::COLOR, Source( self, mEffectColorPropertyIndex ), EqualToConstraint() ) );
273 void EffectsView::SetBackgroundColor( const Vector4& color )
275 mBackgroundColor = color;
278 Vector4 EffectsView::GetBackgroundColor() const
280 return mBackgroundColor;
284 void EffectsView::OnInitialize()
286 //////////////////////////////////////////////////////
288 mCameraForChildren = CameraActor::New();
289 mCameraForChildren.SetParentOrigin(ParentOrigin::CENTER);
291 mActorForChildren = ImageActor::New();
292 mActorForChildren.SetPositionInheritanceMode( Dali::USE_PARENT_POSITION );
293 mActorForChildren.ApplyConstraint( Constraint::New<Vector3>( Actor::SIZE, ParentSource( Actor::SIZE ), EqualToConstraint() ) ); // same size as EffectsView object
294 mActorForChildren.ScaleBy( Vector3(1.0f, -1.0f, 1.0f) );
296 mActorPostFilter = ImageActor::New();
297 mActorPostFilter.SetParentOrigin( ParentOrigin::CENTER );
298 mActorPostFilter.ApplyConstraint( Constraint::New<Vector3>( Actor::SIZE, ParentSource( Actor::SIZE ), EqualToConstraint() ) ); // same size as EffectsView object
299 mActorPostFilter.ScaleBy( Vector3(1.0f, -1.0f, 1.0f) );
300 mActorPostFilter.SetShaderEffect( ShaderEffect::New( "", EFFECTS_VIEW_FRAGMENT_SOURCE ) );
302 // Connect to actor tree
303 Self().Add( mActorPostFilter );
304 Self().Add( mActorForChildren );
305 Self().Add( mCameraForChildren );
310 void EffectsView::OnControlSizeSet(const Vector3& targetSize)
312 mTargetSize = Vector2(targetSize);
314 // if we are already on stage, need to update render target sizes now to reflect the new size of this actor
321 void EffectsView::OnStageDisconnection()
323 const size_t numFilters( mFilters.size() );
324 for( size_t i = 0; i < numFilters; ++i )
326 mFilters[i]->Disable();
330 void EffectsView::SetupFilters()
332 int effectSize = static_cast< int >( Self().GetProperty( mEffectSizePropertyIndex ).Get<float>() );
333 switch( mEffectType )
335 case Toolkit::EffectsView::DROP_SHADOW:
337 SpreadFilter* spreadFilter = static_cast< SpreadFilter* >( mFilters[0] );
338 spreadFilter->SetInputImage( mImageForChildren );
339 spreadFilter->SetOutputImage( mImagePostFilter );
340 spreadFilter->SetRootActor( Self() );
341 spreadFilter->SetBackgroundColor( mBackgroundColor );
342 spreadFilter->SetPixelFormat( mPixelFormat );
343 spreadFilter->SetSize( mTargetSize );
344 spreadFilter->SetSpread( effectSize );
346 BlurTwoPassFilter* blurFilter = static_cast< BlurTwoPassFilter* >( mFilters[1] );
347 blurFilter->SetInputImage( mImagePostFilter );
348 blurFilter->SetOutputImage( mImagePostFilter );
349 blurFilter->SetRootActor( Self() );
350 blurFilter->SetBackgroundColor( mBackgroundColor );
351 blurFilter->SetPixelFormat( mPixelFormat );
352 blurFilter->SetSize( mTargetSize );
354 const float* kernel(NULL);
355 size_t kernelSize(0);
358 case 4: { kernel = BLUR_KERNEL4; kernelSize = sizeof(BLUR_KERNEL4)/sizeof(BLUR_KERNEL4[0]); break; }
359 case 3: { kernel = BLUR_KERNEL3; kernelSize = sizeof(BLUR_KERNEL3)/sizeof(BLUR_KERNEL3[0]); break; }
360 case 2: { kernel = BLUR_KERNEL2; kernelSize = sizeof(BLUR_KERNEL2)/sizeof(BLUR_KERNEL2[0]); break; }
361 case 1: { kernel = BLUR_KERNEL1; kernelSize = sizeof(BLUR_KERNEL1)/sizeof(BLUR_KERNEL1[0]); break; }
363 default: { kernel = BLUR_KERNEL0; kernelSize = sizeof(BLUR_KERNEL0)/sizeof(BLUR_KERNEL0[0]); break; }
365 blurFilter->CreateKernel( kernel, kernelSize );
368 case Toolkit::EffectsView::EMBOSS:
370 SpreadFilter* spreadFilter = static_cast< SpreadFilter* >( mFilters[0] );
371 spreadFilter->SetInputImage( mImageForChildren );
372 spreadFilter->SetOutputImage( mImagePostFilter );
373 spreadFilter->SetRootActor( Self() );
374 spreadFilter->SetBackgroundColor( mBackgroundColor );
375 spreadFilter->SetPixelFormat( Pixel::RGBA8888 );
376 spreadFilter->SetSize( mTargetSize );
377 spreadFilter->SetSpread( effectSize );
379 EmbossFilter* embossFilter = static_cast< EmbossFilter* >( mFilters[1] );
380 embossFilter->SetInputImage( mImagePostFilter );
381 embossFilter->SetOutputImage( mImagePostFilter );
382 embossFilter->SetRootActor( Self() );
383 embossFilter->SetBackgroundColor( mBackgroundColor );
384 embossFilter->SetPixelFormat( Pixel::RGBA8888 );
385 embossFilter->SetSize( mTargetSize );
387 BlurTwoPassFilter* blurFilter = static_cast< BlurTwoPassFilter* >( mFilters[2] );
388 blurFilter->SetInputImage( mImagePostFilter );
389 blurFilter->SetOutputImage( mImagePostFilter );
390 blurFilter->SetRootActor( Self() );
391 blurFilter->SetBackgroundColor( Vector4( 0.5f, 0.5f, 0.5f, 0.0 ) );
392 blurFilter->SetPixelFormat( Pixel::RGBA8888 );
393 blurFilter->SetSize( mTargetSize );
394 blurFilter->CreateKernel( BLUR_KERNEL0, sizeof(BLUR_KERNEL0)/sizeof(BLUR_KERNEL0[0]) );
404 void EffectsView::AllocateResources()
406 if(mTargetSize != mLastSize)
408 mLastSize = mTargetSize;
412 mImageForChildren = FrameBufferImage::New( mTargetSize.width, mTargetSize.height, mPixelFormat, Dali::Image::Unused );
413 mActorForChildren.SetImage(mImageForChildren);
415 mImagePostFilter = FrameBufferImage::New( mTargetSize.width, mTargetSize.height, mPixelFormat, Dali::Image::Unused );
416 mActorPostFilter.SetImage(mImagePostFilter);
422 void EffectsView::SetupCameras()
424 const float cameraPosConstraintScale( 0.5f / tanf(ARBITRARY_FIELD_OF_VIEW * 0.5f) );
426 // Create and place a camera for the children render, corresponding to its render target size
427 mCameraForChildren.SetFieldOfView(ARBITRARY_FIELD_OF_VIEW);
428 // 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
429 mCameraForChildren.SetNearClippingPlane(1.0f);
430 mCameraForChildren.SetAspectRatio(mTargetSize.width / mTargetSize.height);
431 mCameraForChildren.SetType(Dali::Camera::FREE_LOOK); // camera orientation based solely on actor
432 mCameraForChildren.SetPosition(0.0f, 0.0f, mTargetSize.height * cameraPosConstraintScale);
433 mCameraForChildren.SetRotation(Quaternion(M_PI, Vector3::YAXIS));
435 // Children render camera must move when EffectsView object is resized.
436 // This is since we cannot change render target size - so we need to remap the child actors' rendering
437 // accordingly so they still exactly fill the render target.
438 // Note that this means the effective resolution of the child render changes as the EffectsView object
439 // changes size, this is the trade off for not being able to modify render target size
440 // Change camera z position based on EffectsView actor height
441 mCameraForChildren.RemoveConstraints();
442 mCameraForChildren.ApplyConstraint( Constraint::New<float>( Actor::POSITION_Z, ParentSource( Actor::SIZE_HEIGHT ), RelativeToConstraintFloat(cameraPosConstraintScale) ) );
445 void EffectsView::CreateRenderTasks()
447 RenderTaskList taskList = Stage::GetCurrent().GetRenderTaskList();
449 // create render task to render our child actors to offscreen buffer
450 mRenderTaskForChildren = taskList.CreateTask();
451 mRenderTaskForChildren.SetRefreshRate( mRefreshOnDemand ? RenderTask::REFRESH_ONCE : RenderTask::REFRESH_ALWAYS );
452 mRenderTaskForChildren.SetSourceActor( Self() );
453 mRenderTaskForChildren.SetExclusive(true);
454 mRenderTaskForChildren.SetInputEnabled( false );
455 mRenderTaskForChildren.SetClearColor( mBackgroundColor );
456 mRenderTaskForChildren.SetClearEnabled( true );
457 mRenderTaskForChildren.SetTargetFrameBuffer( mImageForChildren );
458 mRenderTaskForChildren.SetCameraActor(mCameraForChildren); // use camera that covers render target exactly
460 // Enable image filters
461 const size_t numFilters( mFilters.size() );
462 for( size_t i = 0; i < numFilters; ++i )
464 mFilters[i]->Enable();
467 // create render task to render result of the image filters to the final offscreen
468 if( mImageForResult )
470 mRenderTaskForResult = taskList.CreateTask();
471 mRenderTaskForResult.SetRefreshRate( mRefreshOnDemand ? RenderTask::REFRESH_ONCE : RenderTask::REFRESH_ALWAYS );
472 mRenderTaskForResult.SetSourceActor( mActorForResult );
473 mRenderTaskForResult.SetExclusive(true);
474 mRenderTaskForResult.SetInputEnabled( false );
475 mRenderTaskForResult.SetClearColor( mBackgroundColor );
476 mRenderTaskForResult.SetClearEnabled( true );
477 mRenderTaskForResult.SetTargetFrameBuffer( mImageForResult );
478 mRenderTaskForResult.SetCameraActor(mCameraForChildren); // use camera that covers render target exactly
482 void EffectsView::RemoveRenderTasks()
484 RenderTaskList taskList = Stage::GetCurrent().GetRenderTaskList();
486 taskList.RemoveTask(mRenderTaskForChildren);
487 taskList.RemoveTask(mRenderTaskForResult);
489 const size_t numFilters( mFilters.size() );
490 for( size_t i = 0; i < numFilters; ++i )
492 mFilters[i]->Disable();
496 void EffectsView::RefreshRenderTasks()
498 RenderTaskList taskList = Stage::GetCurrent().GetRenderTaskList();
500 if( mRenderTaskForChildren )
502 mRenderTaskForChildren.SetRefreshRate( mRefreshOnDemand ? RenderTask::REFRESH_ONCE : RenderTask::REFRESH_ALWAYS );
505 if( mRenderTaskForResult )
507 mRenderTaskForResult.SetRefreshRate( mRefreshOnDemand ? RenderTask::REFRESH_ONCE : RenderTask::REFRESH_ALWAYS );
510 const size_t numFilters( mFilters.size() );
511 for( size_t i = 0; i < numFilters; ++i )
513 mFilters[i]->Refresh();
517 void EffectsView::RemoveFilters()
519 const size_t numFilters( mFilters.size() );
520 for( size_t i = 0; i < numFilters; ++i )
527 } // namespace Internal
529 } // namespace Toolkit