Update toolkit with ResourceImage/Image split
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / controls / effects-view / effects-view-impl.cpp
1 /*
2  * Copyright (c) 2014 Samsung Electronics Co., Ltd.
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  *
16  */
17
18 // CLASS HEADER
19 #include "effects-view-impl.h"
20
21 // EXTERNAL INCLUDES
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>
26
27 // INTERNAL INCLUDES
28 #include "../../filters/blur-two-pass-filter.h"
29 #include "../../filters/emboss-filter.h"
30 #include "../../filters/spread-filter.h"
31
32 namespace Dali
33 {
34
35 namespace Toolkit
36 {
37
38 namespace Internal
39 {
40
41 namespace
42 {
43
44 Dali::BaseHandle Create()
45 {
46   return Toolkit::EffectsView::New();
47 }
48
49 Dali::TypeRegistration mType( typeid(Dali::Toolkit::EffectsView), typeid(Dali::Toolkit::Control), Create );
50
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);
55 // custom properties
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" );
64
65 const char* const EFFECTS_VIEW_FRAGMENT_SOURCE =
66     "void main()\n"
67     "{\n"
68     "  gl_FragColor = uColor;\n"
69     "  gl_FragColor.a *= texture2D( sTexture, vTexCoord).a;\n"
70     "}\n";
71
72 const float BLUR_KERNEL0[] = { 12.0f/16.0f,
73                                2.0f/16.0f, 2.0f/16.0f };
74
75 const float BLUR_KERNEL1[] = { 8.0f/16.0f,
76                                4.0f/16.0f, 4.0f/16.0f };
77
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 };
82
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 };
87
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 };
93
94 } // namespace
95
96 Toolkit::EffectsView EffectsView::New()
97 {
98   EffectsView* effectsView = new EffectsView;
99
100   Toolkit::EffectsView handle = Toolkit::EffectsView( *effectsView );
101
102   // Second-phase init of the implementation
103   // This can only be done after the CustomActor connection has been made...
104   effectsView->Initialize();
105
106   return handle;
107 }
108
109 EffectsView::EffectsView()
110 : Control( CONTROL_BEHAVIOUR_NONE ),
111   mEffectType( Toolkit::EffectsView::INVALID_TYPE ),
112   mPixelFormat( EFFECTS_VIEW_DEFAULT_PIXEL_FORMAT ),
113   mSpread(0.0f),
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)
122 {
123 }
124
125 EffectsView::~EffectsView()
126 {
127   RemoveFilters();
128 }
129
130 void EffectsView::SetType( Toolkit::EffectsView::EffectType type )
131 {
132   if( mEffectType != type )
133   {
134     mEffectType = type;
135
136     RemoveFilters();
137
138     switch( mEffectType )
139     {
140       case Toolkit::EffectsView::DROP_SHADOW:
141       {
142         mFilters.push_back( new SpreadFilter );
143         mFilters.push_back( new BlurTwoPassFilter );
144         break;
145       }
146       case Toolkit::EffectsView::EMBOSS:
147       {
148         mFilters.push_back( new SpreadFilter );
149         mFilters.push_back( new EmbossFilter );
150         mFilters.push_back( new BlurTwoPassFilter );
151         mActorPostFilter.RemoveShaderEffect();
152         break;
153       }
154       default:
155       {
156         break;
157       }
158     }
159   }
160 }
161
162 Toolkit::EffectsView::EffectType EffectsView::GetType() const
163 {
164   return mEffectType;
165 }
166
167 void EffectsView::Enable()
168 {
169   // make sure resources are allocated and start the render tasks processing
170   AllocateResources();
171   CreateRenderTasks();
172 }
173
174 void EffectsView::Disable()
175 {
176   // stop render tasks processing
177   // Note: render target resources are automatically freed since we set the Image::Unused flag
178   RemoveRenderTasks();
179 }
180
181 void EffectsView::Refresh()
182 {
183   RefreshRenderTasks();
184 }
185
186 void EffectsView::SetRefreshOnDemand( bool onDemand )
187 {
188   mRefreshOnDemand = onDemand;
189
190   RefreshRenderTasks();
191 }
192
193 void EffectsView::SetPixelFormat( Pixel::Format pixelFormat )
194 {
195   mPixelFormat = pixelFormat;
196 }
197
198 void EffectsView::SetOutputImage( FrameBufferImage image )
199 {
200   CustomActor self = Self();
201
202   if( mImageForResult != image )
203   {
204     if( !image )
205     {
206       if( mImageForResult )
207       {
208         self.Remove( mActorForResult );
209         mActorForResult.Reset();
210
211         self.Add( mActorPostFilter );
212         self.Add( mActorForChildren );
213       }
214     }
215     else
216     {
217       if( mImageForResult )
218       {
219         self.Remove( mActorForResult );
220       }
221       mActorForResult = Actor::New();
222       mActorForResult.SetParentOrigin( ParentOrigin::CENTER );
223       mActorForResult.SetSize( mTargetSize );
224       mActorForResult.ScaleBy( Vector3(1.0f, -1.0f, 1.0f) );
225
226       Self().Add( mActorForResult );
227       mActorForResult.Add( mActorPostFilter );
228       mActorForResult.Add( mActorForChildren );
229     }
230     mImageForResult = image;
231   }
232 }
233
234 FrameBufferImage EffectsView::GetOutputImage()
235 {
236   return mImageForResult;
237 }
238
239 Property::Index EffectsView::GetEffectSizePropertyIndex() const
240 {
241   return mEffectSizePropertyIndex;
242 }
243
244 Property::Index EffectsView::GetEffectStrengthPropertyIndex() const
245 {
246   return mEffectStrengthPropertyIndex;
247 }
248
249 Property::Index EffectsView::GetEffectOffsetPropertyIndex() const
250 {
251   return mEffectOffsetPropertyIndex;
252 }
253
254 Property::Index EffectsView::GetEffectColorPropertyIndex() const
255 {
256   return mEffectColorPropertyIndex;
257 }
258
259 void EffectsView::SetupProperties()
260 {
261   CustomActor self = Self();
262
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<Vector4>( Actor::COLOR, Source( self, mEffectColorPropertyIndex ), EqualToConstraint() ) );
270 }
271
272 void EffectsView::SetBackgroundColor( const Vector4& color )
273 {
274   mBackgroundColor = color;
275 }
276
277 Vector4 EffectsView::GetBackgroundColor() const
278 {
279   return mBackgroundColor;
280 }
281
282 // From Control
283 void EffectsView::OnInitialize()
284 {
285   //////////////////////////////////////////////////////
286   // Create cameras
287   mCameraForChildren = CameraActor::New();
288   mCameraForChildren.SetParentOrigin(ParentOrigin::CENTER);
289
290   mActorForChildren = ImageActor::New();
291   mActorForChildren.SetPositionInheritanceMode( Dali::USE_PARENT_POSITION );
292   mActorForChildren.ScaleBy( Vector3(1.0f, -1.0f, 1.0f) );
293
294   mActorPostFilter = ImageActor::New();
295   mActorPostFilter.SetParentOrigin( ParentOrigin::CENTER );
296   mActorPostFilter.ScaleBy( Vector3(1.0f, -1.0f, 1.0f) );
297   mActorPostFilter.SetShaderEffect( ShaderEffect::New( "", EFFECTS_VIEW_FRAGMENT_SOURCE ) );
298
299   // Connect to actor tree
300   Self().Add( mActorPostFilter );
301   Self().Add( mActorForChildren );
302   Self().Add( mCameraForChildren );
303
304   SetupProperties();
305 }
306
307 void EffectsView::OnControlSizeSet(const Vector3& targetSize)
308 {
309   mTargetSize = Vector2(targetSize);
310
311   // if we are already on stage, need to update render target sizes now to reflect the new size of this actor
312   if(Self().OnStage())
313   {
314     AllocateResources();
315   }
316
317   if( mActorForResult )
318   {
319     mActorForResult.SetSize( targetSize );
320   }
321   if( mActorForChildren )
322   {
323     mActorForChildren.SetSize( targetSize );
324   }
325   if( mActorPostFilter )
326   {
327     mActorPostFilter.SetSize( targetSize );
328   }
329
330   // Children render camera must move when EffectsView object is resized.
331   // This is since we cannot change render target size - so we need to remap the child actors' rendering
332   // accordingly so they still exactly fill the render target.
333   // Note that this means the effective resolution of the child render changes as the EffectsView object
334   // changes size, this is the trade off for not being able to modify render target size
335   // Change camera z position based on EffectsView actor height
336   if( mCameraForChildren )
337   {
338     const float cameraPosScale( 0.5f / tanf(ARBITRARY_FIELD_OF_VIEW * 0.5f) );
339     mCameraForChildren.SetZ( targetSize.height * cameraPosScale );
340   }
341
342   const size_t numFilters( mFilters.size() );
343   for( size_t i = 0; i < numFilters; ++i )
344   {
345     mFilters[i]->SetSize( mTargetSize );
346   }
347
348 }
349
350 void EffectsView::OnStageDisconnection()
351 {
352   const size_t numFilters( mFilters.size() );
353   for( size_t i = 0; i < numFilters; ++i )
354   {
355     mFilters[i]->Disable();
356   }
357 }
358
359 void EffectsView::SetupFilters()
360 {
361   int effectSize = static_cast< int >( Self().GetProperty( mEffectSizePropertyIndex ).Get<float>() );
362   switch( mEffectType )
363   {
364     case Toolkit::EffectsView::DROP_SHADOW:
365     {
366       SpreadFilter* spreadFilter = static_cast< SpreadFilter* >( mFilters[0] );
367       spreadFilter->SetInputImage( mImageForChildren );
368       spreadFilter->SetOutputImage( mImagePostFilter );
369       spreadFilter->SetRootActor( Self() );
370       spreadFilter->SetBackgroundColor( mBackgroundColor );
371       spreadFilter->SetPixelFormat( mPixelFormat );
372       spreadFilter->SetSize( mTargetSize );
373       spreadFilter->SetSpread( effectSize );
374
375       BlurTwoPassFilter* blurFilter = static_cast< BlurTwoPassFilter* >( mFilters[1] );
376       blurFilter->SetInputImage( mImagePostFilter );
377       blurFilter->SetOutputImage( mImagePostFilter );
378       blurFilter->SetRootActor( Self() );
379       blurFilter->SetBackgroundColor( mBackgroundColor );
380       blurFilter->SetPixelFormat( mPixelFormat );
381       blurFilter->SetSize( mTargetSize );
382
383       const float* kernel(NULL);
384       size_t kernelSize(0);
385       switch( effectSize )
386       {
387         case 4:  {  kernel = BLUR_KERNEL4; kernelSize = sizeof(BLUR_KERNEL4)/sizeof(BLUR_KERNEL4[0]); break; }
388         case 3:  {  kernel = BLUR_KERNEL3; kernelSize = sizeof(BLUR_KERNEL3)/sizeof(BLUR_KERNEL3[0]); break; }
389         case 2:  {  kernel = BLUR_KERNEL2; kernelSize = sizeof(BLUR_KERNEL2)/sizeof(BLUR_KERNEL2[0]); break; }
390         case 1:  {  kernel = BLUR_KERNEL1; kernelSize = sizeof(BLUR_KERNEL1)/sizeof(BLUR_KERNEL1[0]); break; }
391         case 0:
392         default: {  kernel = BLUR_KERNEL0; kernelSize = sizeof(BLUR_KERNEL0)/sizeof(BLUR_KERNEL0[0]); break; }
393       }
394       blurFilter->CreateKernel( kernel, kernelSize );
395       break;
396     }
397     case Toolkit::EffectsView::EMBOSS:
398     {
399       SpreadFilter* spreadFilter = static_cast< SpreadFilter* >( mFilters[0] );
400       spreadFilter->SetInputImage( mImageForChildren );
401       spreadFilter->SetOutputImage( mImagePostFilter );
402       spreadFilter->SetRootActor( Self() );
403       spreadFilter->SetBackgroundColor( mBackgroundColor );
404       spreadFilter->SetPixelFormat( Pixel::RGBA8888 );
405       spreadFilter->SetSize( mTargetSize );
406       spreadFilter->SetSpread( effectSize );
407
408       EmbossFilter* embossFilter = static_cast< EmbossFilter* >( mFilters[1] );
409       embossFilter->SetInputImage( mImagePostFilter );
410       embossFilter->SetOutputImage( mImagePostFilter );
411       embossFilter->SetRootActor( Self() );
412       embossFilter->SetBackgroundColor( mBackgroundColor );
413       embossFilter->SetPixelFormat( Pixel::RGBA8888 );
414       embossFilter->SetSize( mTargetSize );
415
416       BlurTwoPassFilter* blurFilter = static_cast< BlurTwoPassFilter* >( mFilters[2] );
417       blurFilter->SetInputImage( mImagePostFilter );
418       blurFilter->SetOutputImage( mImagePostFilter );
419       blurFilter->SetRootActor( Self() );
420       blurFilter->SetBackgroundColor( Vector4( 0.5f, 0.5f, 0.5f, 0.0 ) );
421       blurFilter->SetPixelFormat( Pixel::RGBA8888 );
422       blurFilter->SetSize( mTargetSize );
423       blurFilter->CreateKernel( BLUR_KERNEL0, sizeof(BLUR_KERNEL0)/sizeof(BLUR_KERNEL0[0]) );
424
425       break;
426     }
427     default:
428     {
429       break;
430     }
431   }
432 }
433 void EffectsView::AllocateResources()
434 {
435   if(mTargetSize != mLastSize)
436   {
437     mLastSize = mTargetSize;
438
439     SetupCameras();
440
441     mImageForChildren = FrameBufferImage::New( mTargetSize.width, mTargetSize.height, mPixelFormat, Dali::Image::UNUSED );
442     mActorForChildren.SetImage(mImageForChildren);
443
444     mImagePostFilter = FrameBufferImage::New( mTargetSize.width, mTargetSize.height, mPixelFormat, Dali::Image::UNUSED );
445     mActorPostFilter.SetImage(mImagePostFilter);
446
447     SetupFilters();
448   }
449 }
450
451 void EffectsView::SetupCameras()
452 {
453   const float cameraPosScale( 0.5f / tanf(ARBITRARY_FIELD_OF_VIEW * 0.5f) );
454
455   // Create and place a camera for the children render, corresponding to its render target size
456   mCameraForChildren.SetFieldOfView(ARBITRARY_FIELD_OF_VIEW);
457   // 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
458   mCameraForChildren.SetNearClippingPlane(1.0f);
459   mCameraForChildren.SetAspectRatio(mTargetSize.width / mTargetSize.height);
460   mCameraForChildren.SetType(Dali::Camera::FREE_LOOK); // camera orientation based solely on actor
461   mCameraForChildren.SetPosition(0.0f, 0.0f, mTargetSize.height * cameraPosScale);
462   mCameraForChildren.SetRotation(Quaternion(M_PI, Vector3::YAXIS));
463   mCameraForChildren.SetZ( mTargetSize.height * cameraPosScale );
464 }
465
466 void EffectsView::CreateRenderTasks()
467 {
468   RenderTaskList taskList = Stage::GetCurrent().GetRenderTaskList();
469
470   // create render task to render our child actors to offscreen buffer
471   mRenderTaskForChildren = taskList.CreateTask();
472   mRenderTaskForChildren.SetRefreshRate( mRefreshOnDemand ? RenderTask::REFRESH_ONCE : RenderTask::REFRESH_ALWAYS );
473   mRenderTaskForChildren.SetSourceActor( Self() );
474   mRenderTaskForChildren.SetExclusive(true);
475   mRenderTaskForChildren.SetInputEnabled( false );
476   mRenderTaskForChildren.SetClearColor( mBackgroundColor );
477   mRenderTaskForChildren.SetClearEnabled( true );
478   mRenderTaskForChildren.SetTargetFrameBuffer( mImageForChildren );
479   mRenderTaskForChildren.SetCameraActor(mCameraForChildren); // use camera that covers render target exactly
480
481   // Enable image filters
482   const size_t numFilters( mFilters.size() );
483   for( size_t i = 0; i < numFilters; ++i )
484   {
485     mFilters[i]->Enable();
486   }
487
488   // create render task to render result of the image filters to the final offscreen
489   if( mImageForResult )
490   {
491     mRenderTaskForResult = taskList.CreateTask();
492     mRenderTaskForResult.SetRefreshRate( mRefreshOnDemand ? RenderTask::REFRESH_ONCE : RenderTask::REFRESH_ALWAYS );
493     mRenderTaskForResult.SetSourceActor( mActorForResult );
494     mRenderTaskForResult.SetExclusive(true);
495     mRenderTaskForResult.SetInputEnabled( false );
496     mRenderTaskForResult.SetClearColor( mBackgroundColor );
497     mRenderTaskForResult.SetClearEnabled( true );
498     mRenderTaskForResult.SetTargetFrameBuffer( mImageForResult );
499     mRenderTaskForResult.SetCameraActor(mCameraForChildren); // use camera that covers render target exactly
500   }
501 }
502
503 void EffectsView::RemoveRenderTasks()
504 {
505   RenderTaskList taskList = Stage::GetCurrent().GetRenderTaskList();
506
507   taskList.RemoveTask(mRenderTaskForChildren);
508   taskList.RemoveTask(mRenderTaskForResult);
509
510   const size_t numFilters( mFilters.size() );
511   for( size_t i = 0; i < numFilters; ++i )
512   {
513     mFilters[i]->Disable();
514   }
515 }
516
517 void EffectsView::RefreshRenderTasks()
518 {
519   RenderTaskList taskList = Stage::GetCurrent().GetRenderTaskList();
520
521   if( mRenderTaskForChildren )
522   {
523     mRenderTaskForChildren.SetRefreshRate( mRefreshOnDemand ? RenderTask::REFRESH_ONCE : RenderTask::REFRESH_ALWAYS );
524   }
525
526   if( mRenderTaskForResult )
527   {
528     mRenderTaskForResult.SetRefreshRate( mRefreshOnDemand ? RenderTask::REFRESH_ONCE : RenderTask::REFRESH_ALWAYS );
529   }
530
531   const size_t numFilters( mFilters.size() );
532   for( size_t i = 0; i < numFilters; ++i )
533   {
534     mFilters[i]->Refresh();
535   }
536 }
537
538 void EffectsView::RemoveFilters()
539 {
540   const size_t numFilters( mFilters.size() );
541   for( size_t i = 0; i < numFilters; ++i )
542   {
543     delete mFilters[i];
544   }
545   mFilters.clear();
546 }
547
548 } // namespace Internal
549
550 } // namespace Toolkit
551
552 } // namespace Dali