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/constraint.h>
23 #include <dali/public-api/animation/constraints.h>
24 #include <dali/public-api/common/stage.h>
25 #include <dali/public-api/object/type-registry.h>
26 #include <dali/devel-api/object/type-registry-helper.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_TYPE_REGISTRATION_BEGIN( Toolkit::EffectsView, Toolkit::Control, Create )
52 DALI_TYPE_REGISTRATION_END()
54 const Pixel::Format EFFECTS_VIEW_DEFAULT_PIXEL_FORMAT = Pixel::RGBA8888;
55 const float ARBITRARY_FIELD_OF_VIEW = Math::PI / 4.0f;
56 const Vector4 EFFECTS_VIEW_DEFAULT_BACKGROUND_COLOR( 1.0f, 1.0f, 1.0f, 0.0 );
57 const bool EFFECTS_VIEW_REFRESH_ON_DEMAND(false);
60 const char* const EFFECT_SIZE_PROPERTY_NAME = "EffectSize";
61 const char* const EFFECT_STRENGTH_PROPERTY_NAME = "EffectStrength";
62 const char* const EFFECT_OFFSET_PROPERTY_NAME = "EffectOffset";
63 const char* const EFFECT_COLOR_PROPERTY_NAME = "EffectColor";
65 const float EFFECT_SIZE_DEFAULT( 1.0f );
66 const float EFFECT_STRENGTH_DEFAULT( 0.5f );
67 const Vector3 EFFECT_OFFSET_DEFAULT( 0.0f, 0.0f, 0.0f );
68 const Vector4 EFFECT_COLOR_DEFAULT( Color::WHITE );
70 const char* const EFFECTS_VIEW_FRAGMENT_SOURCE =
73 " gl_FragColor = uColor;\n"
74 " gl_FragColor.a *= texture2D( sTexture, vTexCoord).a;\n"
77 const float BLUR_KERNEL0[] = { 12.0f/16.0f,
78 2.0f/16.0f, 2.0f/16.0f };
80 const float BLUR_KERNEL1[] = { 8.0f/16.0f,
81 4.0f/16.0f, 4.0f/16.0f };
83 const float BLUR_KERNEL2[] = { 6.0f/16.0f,
84 2.5f/16.0f, 2.5f/16.0f,
85 1.5f/16.0f, 1.5f/16.0f,
86 1.0f/16.0f, 1.0f/16.0f };
88 const float BLUR_KERNEL3[] = { 4.0f/16.0f,
89 3.0f/16.0f, 2.0f/16.0f,
90 2.0f/16.0f, 2.0f/16.0f,
91 1.0f/16.0f, 1.0f/16.0f };
93 const float BLUR_KERNEL4[] = { 3.0f/16.0f,
94 2.5f/16.0f, 2.5f/16.0f,
95 1.75f/16.0f, 1.75f/16.0f,
96 1.25f/16.0f, 1.25f/16.0f,
97 1.0f/16.0f, 1.0f/16.0f };
101 Toolkit::EffectsView EffectsView::New()
103 EffectsView* effectsView = new EffectsView;
105 Toolkit::EffectsView handle = Toolkit::EffectsView( *effectsView );
107 // Second-phase init of the implementation
108 // This can only be done after the CustomActor connection has been made...
109 effectsView->Initialize();
114 EffectsView::EffectsView()
115 : Control( ControlBehaviour( ACTOR_BEHAVIOUR_NONE ) ),
116 mEffectType( Toolkit::EffectsView::INVALID_TYPE ),
117 mPixelFormat( EFFECTS_VIEW_DEFAULT_PIXEL_FORMAT ),
119 mBackgroundColor( EFFECTS_VIEW_DEFAULT_BACKGROUND_COLOR ),
120 mTargetSize( Vector2::ZERO ),
121 mLastSize( Vector2::ZERO ),
122 mRefreshOnDemand(EFFECTS_VIEW_REFRESH_ON_DEMAND),
123 mEffectSizePropertyIndex(Property::INVALID_INDEX),
124 mEffectStrengthPropertyIndex(Property::INVALID_INDEX),
125 mEffectOffsetPropertyIndex(Property::INVALID_INDEX),
126 mEffectColorPropertyIndex(Property::INVALID_INDEX)
130 EffectsView::~EffectsView()
135 void EffectsView::SetType( Toolkit::EffectsView::EffectType type )
137 if( mEffectType != type )
143 switch( mEffectType )
145 case Toolkit::EffectsView::DROP_SHADOW:
147 mFilters.push_back( new SpreadFilter );
148 mFilters.push_back( new BlurTwoPassFilter );
151 case Toolkit::EffectsView::EMBOSS:
153 mFilters.push_back( new SpreadFilter );
154 mFilters.push_back( new EmbossFilter );
155 mFilters.push_back( new BlurTwoPassFilter );
156 mActorPostFilter.RemoveShaderEffect();
167 Toolkit::EffectsView::EffectType EffectsView::GetType() const
172 void EffectsView::Enable()
174 // make sure resources are allocated and start the render tasks processing
179 void EffectsView::Disable()
181 // stop render tasks processing
182 // Note: render target resources are automatically freed since we set the Image::Unused flag
186 void EffectsView::Refresh()
188 RefreshRenderTasks();
191 void EffectsView::SetRefreshOnDemand( bool onDemand )
193 mRefreshOnDemand = onDemand;
195 RefreshRenderTasks();
198 void EffectsView::SetPixelFormat( Pixel::Format pixelFormat )
200 mPixelFormat = pixelFormat;
203 void EffectsView::SetOutputImage( FrameBufferImage image )
205 CustomActor self = Self();
207 if( mImageForResult != image )
211 if( mImageForResult )
213 self.Remove( mActorForResult );
214 mActorForResult.Reset();
216 self.Add( mActorPostFilter );
217 self.Add( mActorForChildren );
222 if( mImageForResult )
224 self.Remove( mActorForResult );
226 mActorForResult = Actor::New();
227 mActorForResult.SetParentOrigin( ParentOrigin::CENTER );
228 mActorForResult.SetSize( mTargetSize );
229 mActorForResult.ScaleBy( Vector3(1.0f, -1.0f, 1.0f) );
231 Self().Add( mActorForResult );
232 mActorForResult.Add( mActorPostFilter );
233 mActorForResult.Add( mActorForChildren );
235 mImageForResult = image;
239 FrameBufferImage EffectsView::GetOutputImage()
241 return mImageForResult;
244 Property::Index EffectsView::GetEffectSizePropertyIndex() const
246 return mEffectSizePropertyIndex;
249 Property::Index EffectsView::GetEffectStrengthPropertyIndex() const
251 return mEffectStrengthPropertyIndex;
254 Property::Index EffectsView::GetEffectOffsetPropertyIndex() const
256 return mEffectOffsetPropertyIndex;
259 Property::Index EffectsView::GetEffectColorPropertyIndex() const
261 return mEffectColorPropertyIndex;
264 void EffectsView::SetupProperties()
266 CustomActor self = Self();
268 // Register a property that the user can control the drop shadow offset
269 mEffectSizePropertyIndex = self.RegisterProperty(EFFECT_SIZE_PROPERTY_NAME, EFFECT_SIZE_DEFAULT, Property::READ_WRITE);
270 mEffectStrengthPropertyIndex = self.RegisterProperty(EFFECT_STRENGTH_PROPERTY_NAME, EFFECT_STRENGTH_DEFAULT, Property::READ_WRITE);
271 mEffectOffsetPropertyIndex = self.RegisterProperty(EFFECT_OFFSET_PROPERTY_NAME, EFFECT_OFFSET_DEFAULT);
272 mEffectColorPropertyIndex = self.RegisterProperty(EFFECT_COLOR_PROPERTY_NAME, EFFECT_COLOR_DEFAULT);
274 Constraint positionConstraint = Constraint::New<Vector3>( mActorPostFilter, Actor::Property::POSITION, EqualToConstraint() );
275 positionConstraint.AddSource( Source( self, mEffectOffsetPropertyIndex ) );
276 positionConstraint.Apply();
278 Constraint colorConstraint = Constraint::New<Vector4>( mActorPostFilter, Actor::Property::COLOR, EqualToConstraint() );
279 colorConstraint.AddSource( Source( self, mEffectColorPropertyIndex ) );
280 colorConstraint.Apply();
283 void EffectsView::SetBackgroundColor( const Vector4& color )
285 mBackgroundColor = color;
288 Vector4 EffectsView::GetBackgroundColor() const
290 return mBackgroundColor;
294 void EffectsView::OnInitialize()
296 //////////////////////////////////////////////////////
298 mCameraForChildren = CameraActor::New();
299 mCameraForChildren.SetParentOrigin(ParentOrigin::CENTER);
301 mActorForChildren = ImageActor::New();
302 mActorForChildren.SetParentOrigin( ParentOrigin::CENTER );
303 mActorForChildren.ScaleBy( Vector3(1.0f, -1.0f, 1.0f) );
305 mActorPostFilter = ImageActor::New();
306 mActorPostFilter.SetParentOrigin( ParentOrigin::CENTER );
307 mActorPostFilter.ScaleBy( Vector3(1.0f, -1.0f, 1.0f) );
308 mActorPostFilter.SetShaderEffect( ShaderEffect::New( "", EFFECTS_VIEW_FRAGMENT_SOURCE ) );
310 // Connect to actor tree
311 Self().Add( mActorPostFilter );
312 Self().Add( mActorForChildren );
313 Self().Add( mCameraForChildren );
318 void EffectsView::OnSizeSet(const Vector3& targetSize)
320 Control::OnSizeSet( targetSize );
322 mTargetSize = Vector2(targetSize);
324 // if we are already on stage, need to update render target sizes now to reflect the new size of this actor
330 if( mActorForResult )
332 mActorForResult.SetSize( targetSize );
334 if( mActorForChildren )
336 mActorForChildren.SetSize( targetSize );
338 if( mActorPostFilter )
340 mActorPostFilter.SetSize( targetSize );
343 // Children render camera must move when EffectsView object is resized.
344 // This is since we cannot change render target size - so we need to remap the child actors' rendering
345 // accordingly so they still exactly fill the render target.
346 // Note that this means the effective resolution of the child render changes as the EffectsView object
347 // changes size, this is the trade off for not being able to modify render target size
348 // Change camera z position based on EffectsView actor height
349 if( mCameraForChildren )
351 const float cameraPosScale( 0.5f / tanf(ARBITRARY_FIELD_OF_VIEW * 0.5f) );
352 mCameraForChildren.SetZ( targetSize.height * cameraPosScale );
355 const size_t numFilters( mFilters.size() );
356 for( size_t i = 0; i < numFilters; ++i )
358 mFilters[i]->SetSize( mTargetSize );
363 void EffectsView::OnStageDisconnection()
365 const size_t numFilters( mFilters.size() );
366 for( size_t i = 0; i < numFilters; ++i )
368 mFilters[i]->Disable();
371 Control::OnStageDisconnection();
374 void EffectsView::SetupFilters()
376 int effectSize = static_cast< int >( Self().GetProperty( mEffectSizePropertyIndex ).Get<float>() );
377 switch( mEffectType )
379 case Toolkit::EffectsView::DROP_SHADOW:
381 SpreadFilter* spreadFilter = static_cast< SpreadFilter* >( mFilters[0] );
382 spreadFilter->SetInputImage( mImageForChildren );
383 spreadFilter->SetOutputImage( mImagePostFilter );
384 spreadFilter->SetRootActor( Self() );
385 spreadFilter->SetBackgroundColor( mBackgroundColor );
386 spreadFilter->SetPixelFormat( mPixelFormat );
387 spreadFilter->SetSize( mTargetSize );
388 spreadFilter->SetSpread( effectSize );
390 BlurTwoPassFilter* blurFilter = static_cast< BlurTwoPassFilter* >( mFilters[1] );
391 blurFilter->SetInputImage( mImagePostFilter );
392 blurFilter->SetOutputImage( mImagePostFilter );
393 blurFilter->SetRootActor( Self() );
394 blurFilter->SetBackgroundColor( mBackgroundColor );
395 blurFilter->SetPixelFormat( mPixelFormat );
396 blurFilter->SetSize( mTargetSize );
398 const float* kernel(NULL);
399 size_t kernelSize(0);
402 case 4: { kernel = BLUR_KERNEL4; kernelSize = sizeof(BLUR_KERNEL4)/sizeof(BLUR_KERNEL4[0]); break; }
403 case 3: { kernel = BLUR_KERNEL3; kernelSize = sizeof(BLUR_KERNEL3)/sizeof(BLUR_KERNEL3[0]); break; }
404 case 2: { kernel = BLUR_KERNEL2; kernelSize = sizeof(BLUR_KERNEL2)/sizeof(BLUR_KERNEL2[0]); break; }
405 case 1: { kernel = BLUR_KERNEL1; kernelSize = sizeof(BLUR_KERNEL1)/sizeof(BLUR_KERNEL1[0]); break; }
407 default: { kernel = BLUR_KERNEL0; kernelSize = sizeof(BLUR_KERNEL0)/sizeof(BLUR_KERNEL0[0]); break; }
409 blurFilter->CreateKernel( kernel, kernelSize );
412 case Toolkit::EffectsView::EMBOSS:
414 SpreadFilter* spreadFilter = static_cast< SpreadFilter* >( mFilters[0] );
415 spreadFilter->SetInputImage( mImageForChildren );
416 spreadFilter->SetOutputImage( mImagePostFilter );
417 spreadFilter->SetRootActor( Self() );
418 spreadFilter->SetBackgroundColor( mBackgroundColor );
419 spreadFilter->SetPixelFormat( Pixel::RGBA8888 );
420 spreadFilter->SetSize( mTargetSize );
421 spreadFilter->SetSpread( effectSize );
423 EmbossFilter* embossFilter = static_cast< EmbossFilter* >( mFilters[1] );
424 embossFilter->SetInputImage( mImagePostFilter );
425 embossFilter->SetOutputImage( mImagePostFilter );
426 embossFilter->SetRootActor( Self() );
427 embossFilter->SetBackgroundColor( mBackgroundColor );
428 embossFilter->SetPixelFormat( Pixel::RGBA8888 );
429 embossFilter->SetSize( mTargetSize );
431 BlurTwoPassFilter* blurFilter = static_cast< BlurTwoPassFilter* >( mFilters[2] );
432 blurFilter->SetInputImage( mImagePostFilter );
433 blurFilter->SetOutputImage( mImagePostFilter );
434 blurFilter->SetRootActor( Self() );
435 blurFilter->SetBackgroundColor( Vector4( 0.5f, 0.5f, 0.5f, 0.0 ) );
436 blurFilter->SetPixelFormat( Pixel::RGBA8888 );
437 blurFilter->SetSize( mTargetSize );
438 blurFilter->CreateKernel( BLUR_KERNEL0, sizeof(BLUR_KERNEL0)/sizeof(BLUR_KERNEL0[0]) );
448 void EffectsView::AllocateResources()
450 if(mTargetSize != mLastSize)
452 mLastSize = mTargetSize;
456 mImageForChildren = FrameBufferImage::New( mTargetSize.width, mTargetSize.height, mPixelFormat, Dali::Image::UNUSED );
457 mActorForChildren.SetImage(mImageForChildren);
459 mImagePostFilter = FrameBufferImage::New( mTargetSize.width, mTargetSize.height, mPixelFormat, Dali::Image::UNUSED );
460 mActorPostFilter.SetImage(mImagePostFilter);
466 void EffectsView::SetupCameras()
468 const float cameraPosScale( 0.5f / tanf(ARBITRARY_FIELD_OF_VIEW * 0.5f) );
470 // Create and place a camera for the children render, corresponding to its render target size
471 mCameraForChildren.SetFieldOfView(ARBITRARY_FIELD_OF_VIEW);
472 // 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
473 mCameraForChildren.SetNearClippingPlane(1.0f);
474 mCameraForChildren.SetAspectRatio(mTargetSize.width / mTargetSize.height);
475 mCameraForChildren.SetType(Dali::Camera::FREE_LOOK); // camera orientation based solely on actor
476 mCameraForChildren.SetPosition(0.0f, 0.0f, mTargetSize.height * cameraPosScale);
477 mCameraForChildren.SetZ( mTargetSize.height * cameraPosScale );
480 void EffectsView::CreateRenderTasks()
482 RenderTaskList taskList = Stage::GetCurrent().GetRenderTaskList();
484 // create render task to render our child actors to offscreen buffer
485 mRenderTaskForChildren = taskList.CreateTask();
486 mRenderTaskForChildren.SetRefreshRate( mRefreshOnDemand ? RenderTask::REFRESH_ONCE : RenderTask::REFRESH_ALWAYS );
487 mRenderTaskForChildren.SetSourceActor( Self() );
488 mRenderTaskForChildren.SetExclusive(true);
489 mRenderTaskForChildren.SetInputEnabled( false );
490 mRenderTaskForChildren.SetClearColor( mBackgroundColor );
491 mRenderTaskForChildren.SetClearEnabled( true );
492 mRenderTaskForChildren.SetTargetFrameBuffer( mImageForChildren );
493 mRenderTaskForChildren.SetCameraActor(mCameraForChildren); // use camera that covers render target exactly
495 // Enable image filters
496 const size_t numFilters( mFilters.size() );
497 for( size_t i = 0; i < numFilters; ++i )
499 mFilters[i]->Enable();
502 // create render task to render result of the image filters to the final offscreen
503 if( mImageForResult )
505 mRenderTaskForResult = taskList.CreateTask();
506 mRenderTaskForResult.SetRefreshRate( mRefreshOnDemand ? RenderTask::REFRESH_ONCE : RenderTask::REFRESH_ALWAYS );
507 mRenderTaskForResult.SetSourceActor( mActorForResult );
508 mRenderTaskForResult.SetExclusive(true);
509 mRenderTaskForResult.SetInputEnabled( false );
510 mRenderTaskForResult.SetClearColor( mBackgroundColor );
511 mRenderTaskForResult.SetClearEnabled( true );
512 mRenderTaskForResult.SetTargetFrameBuffer( mImageForResult );
513 mRenderTaskForResult.SetCameraActor(mCameraForChildren); // use camera that covers render target exactly
517 void EffectsView::RemoveRenderTasks()
519 RenderTaskList taskList = Stage::GetCurrent().GetRenderTaskList();
521 taskList.RemoveTask(mRenderTaskForChildren);
522 taskList.RemoveTask(mRenderTaskForResult);
524 const size_t numFilters( mFilters.size() );
525 for( size_t i = 0; i < numFilters; ++i )
527 mFilters[i]->Disable();
531 void EffectsView::RefreshRenderTasks()
533 RenderTaskList taskList = Stage::GetCurrent().GetRenderTaskList();
535 if( mRenderTaskForChildren )
537 mRenderTaskForChildren.SetRefreshRate( mRefreshOnDemand ? RenderTask::REFRESH_ONCE : RenderTask::REFRESH_ALWAYS );
540 if( mRenderTaskForResult )
542 mRenderTaskForResult.SetRefreshRate( mRefreshOnDemand ? RenderTask::REFRESH_ONCE : RenderTask::REFRESH_ALWAYS );
545 const size_t numFilters( mFilters.size() );
546 for( size_t i = 0; i < numFilters; ++i )
548 mFilters[i]->Refresh();
552 void EffectsView::RemoveFilters()
554 const size_t numFilters( mFilters.size() );
555 for( size_t i = 0; i < numFilters; ++i )
562 } // namespace Internal
564 } // namespace Toolkit