Merge remote-tracking branch 'origin/tizen' into devel/new_mesh
[platform/core/uifw/dali-demo.git] / examples / dissolve-effect / dissolve-effect-example.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 // EXTERNAL INCLUDES
19 #include <math.h>
20
21 // INTERNAL INCLUDES
22 #include "shared/view.h"
23
24 #include <dali/dali.h>
25 #include <dali-toolkit/dali-toolkit.h>
26 #include <dali-toolkit/devel-api/shader-effects/dissolve-effect.h>
27
28 using namespace Dali;
29
30 using Dali::Toolkit::TextLabel;
31
32 // LOCAL STUFF
33 namespace
34 {
35
36 const char * const TOOLBAR_IMAGE( DALI_IMAGE_DIR "top-bar.png" );
37 const char * const APPLICATION_TITLE_HIGHP( "Dissolve Effect(highp)" );
38 const char * const APPLICATION_TITLE_MEDIUMP( "Dissolve Effect(mediump)" );
39 const char * const EFFECT_HIGHP_IMAGE( DALI_IMAGE_DIR "icon-highp.png" );
40 const char * const EFFECT_MEDIUMP_IMAGE( DALI_IMAGE_DIR "icon-mediump.png" );
41 const char * const PLAY_ICON( DALI_IMAGE_DIR "icon-play.png" );
42 const char * const STOP_ICON( DALI_IMAGE_DIR "icon-stop.png" );
43
44 const char* IMAGES[] =
45 {
46   DALI_IMAGE_DIR "gallery-large-1.jpg",
47   DALI_IMAGE_DIR "gallery-large-2.jpg",
48   DALI_IMAGE_DIR "gallery-large-3.jpg",
49   DALI_IMAGE_DIR "gallery-large-4.jpg",
50   DALI_IMAGE_DIR "gallery-large-5.jpg",
51   DALI_IMAGE_DIR "gallery-large-6.jpg",
52   DALI_IMAGE_DIR "gallery-large-7.jpg",
53   DALI_IMAGE_DIR "gallery-large-8.jpg",
54   DALI_IMAGE_DIR "gallery-large-9.jpg",
55   DALI_IMAGE_DIR "gallery-large-10.jpg",
56   DALI_IMAGE_DIR "gallery-large-11.jpg",
57   DALI_IMAGE_DIR "gallery-large-12.jpg",
58   DALI_IMAGE_DIR "gallery-large-13.jpg",
59   DALI_IMAGE_DIR "gallery-large-14.jpg",
60   DALI_IMAGE_DIR "gallery-large-15.jpg",
61   DALI_IMAGE_DIR "gallery-large-16.jpg",
62   DALI_IMAGE_DIR "gallery-large-17.jpg",
63   DALI_IMAGE_DIR "gallery-large-18.jpg",
64   DALI_IMAGE_DIR "gallery-large-19.jpg",
65   DALI_IMAGE_DIR "gallery-large-20.jpg",
66   DALI_IMAGE_DIR "gallery-large-21.jpg",
67 };
68
69 const int NUM_IMAGES( sizeof(IMAGES) / sizeof(IMAGES[0]) );
70
71 // The duration of the current image staying on screen when slideshow is on
72 const int VIEWINGTIME = 2000; // 2 seconds
73
74 const float TRANSITION_DURATION = 2.5f; //2.5 second
75
76 const float INITIAL_DEPTH = -10.0f;
77
78 /**
79  * @brief Load an image, scaled-down to no more than the stage dimensions.
80  *
81  * Uses image scaling mode SCALE_TO_FILL to resize the image at
82  * load time to cover the entire stage with pixels with no borders,
83  * and filter mode BOX_THEN_LINEAR to sample the image with
84  * maximum quality.
85  */
86 ResourceImage LoadStageFillingImage( const char * const imagePath )
87 {
88   Size stageSize = Stage::GetCurrent().GetSize();
89   return ResourceImage::New( imagePath, ImageDimensions( stageSize.x, stageSize.y ), Dali::FittingMode::SCALE_TO_FILL, Dali::SamplingMode::BOX_THEN_LINEAR );
90 }
91
92 } // namespace
93
94 class DissolveEffectApp : public ConnectionTracker
95 {
96 public:
97
98   /**
99    * Constructor
100    * @param application class, stored as reference
101    */
102   DissolveEffectApp( Application& application );
103
104   ~DissolveEffectApp();
105
106 private:
107
108   /**
109    * This method gets called once the main loop of application is up and running
110    */
111   void OnInit( Application& application );
112   /**
113    * PanGesture callback. This method gets called when the pan gesture is detected.
114    * @param[in] actor The actor receiving the pan gesture.
115    * @param[in] gesture The detected pan gesture.
116    */
117   void OnPanGesture( Actor actor, const PanGesture& gesture );
118
119   /**
120    * Set up the animations for transition
121    * @param[in] position The point ( locates within rectange {(0,0),(0,1),(1,0),(1,1)} ) passing through the central line of the dissolve effect
122    * @param[in] displacement The direction of the central line of the dissolve effect
123    */
124   void StartTransition(Vector2 position, Vector2 displacement);
125   /**
126    * Callback function of effect-switch button
127    * Change the precision of the effect shader when the effect button is clicked
128    * @param[in] button The handle of the clicked button
129    */
130   bool OnEffectButtonClicked( Toolkit::Button button );
131   /**
132    * Callback function of slideshow button
133    * Start or stop the automatical image display when the slideshow button is clicked
134    * @param[in] button The handle of the clicked button
135    */
136   bool OnSildeshowButtonClicked( Toolkit::Button button );
137   /**
138    * Callback function of cube transition completed signal
139    * @param[in] effect The cube effect used for the transition
140    * @param[in] imageActor The target imageActor of the completed transition
141    */
142   void OnTransitionCompleted(Animation& source);
143   /**
144    * Callback function of timer tick
145    * The timer is used to count the image display duration after cube transition in slideshow,
146    */
147   bool OnTimerTick();
148
149   /**
150    * Main key event handler
151    */
152   void OnKeyEvent(const KeyEvent& event);
153
154 private:
155   Application&                    mApplication;
156   Toolkit::Control                mView;
157   Toolkit::ToolBar                mToolBar;
158   Layer                           mContent;
159   Toolkit::TextLabel              mTitleActor;
160   Actor                           mParent;
161
162   ImageActor                      mCurrentImage;
163   ImageActor                      mNextImage;
164   unsigned int                    mIndex;
165
166   ShaderEffect                    mCurrentImageEffect;
167   ShaderEffect                    mNextImageEffect;
168   bool                            mUseHighPrecision;
169   Animation                       mAnimation;
170
171   PanGestureDetector              mPanGestureDetector;
172   bool                            mIsTransiting;
173
174   bool                            mSlideshow;
175   Timer                           mViewTimer;
176   bool                            mTimerReady;
177   unsigned int                    mCentralLineIndex;
178
179   Image                           mIconPlay;
180   Image                           mIconStop;
181   Toolkit::PushButton             mPlayStopButton;
182
183   Image                           mIconHighP;
184   Image                           mIconMediumP;
185   Toolkit::PushButton             mEffectChangeButton;
186 };
187
188 DissolveEffectApp::DissolveEffectApp( Application& application )
189 : mApplication( application ),
190   mIndex( 0 ),
191   mUseHighPrecision(true),
192   mIsTransiting( false ),
193   mSlideshow( false ),
194   mTimerReady( false ),
195   mCentralLineIndex( 0 )
196 {
197   mApplication.InitSignal().Connect( this, &DissolveEffectApp::OnInit );
198 }
199
200 DissolveEffectApp::~DissolveEffectApp()
201 {
202   //Nothing to do
203 }
204
205 void DissolveEffectApp::OnInit( Application& application )
206 {
207   Stage::GetCurrent().KeyEventSignal().Connect(this, &DissolveEffectApp::OnKeyEvent);
208
209   // Creates a default view with a default tool bar, the view is added to the stage.
210   mContent = DemoHelper::CreateView( application, mView,mToolBar, "", TOOLBAR_IMAGE, "" );
211
212   // Add an effect-changing button on the right of the tool bar.
213   mIconHighP = ResourceImage::New( EFFECT_HIGHP_IMAGE );
214   mIconMediumP = ResourceImage::New( EFFECT_MEDIUMP_IMAGE );
215   mEffectChangeButton = Toolkit::PushButton::New();
216   mEffectChangeButton.SetBackgroundImage(mIconHighP);
217   mEffectChangeButton.ClickedSignal().Connect( this, &DissolveEffectApp::OnEffectButtonClicked );
218   mToolBar.AddControl( mEffectChangeButton, DemoHelper::DEFAULT_VIEW_STYLE.mToolBarButtonPercentage, Toolkit::Alignment::HorizontalRight, DemoHelper::DEFAULT_MODE_SWITCH_PADDING );
219
220   // Add title to the tool bar.
221   mTitleActor = DemoHelper::CreateToolBarLabel( APPLICATION_TITLE_HIGHP );
222   mToolBar.AddControl( mTitleActor, DemoHelper::DEFAULT_VIEW_STYLE.mToolBarTitlePercentage, Toolkit::Alignment::HorizontalCenter );
223
224   // Add an slide-show button on the right of the title
225   mIconPlay = ResourceImage::New( PLAY_ICON );
226   mIconStop = ResourceImage::New( STOP_ICON );
227   mPlayStopButton = Toolkit::PushButton::New();
228   mPlayStopButton.SetBackgroundImage( mIconPlay );
229   mPlayStopButton.ClickedSignal().Connect( this, &DissolveEffectApp::OnSildeshowButtonClicked );
230   mToolBar.AddControl( mPlayStopButton, DemoHelper::DEFAULT_VIEW_STYLE.mToolBarButtonPercentage, Toolkit::Alignment::HorizontalCenter, DemoHelper::DEFAULT_PLAY_PADDING );
231
232   // use pan gesture to detect the cursor or finger movement
233   mPanGestureDetector = PanGestureDetector::New();
234   mPanGestureDetector.DetectedSignal().Connect( this, &DissolveEffectApp::OnPanGesture );
235
236   // create the dissolve effect object
237   mCurrentImageEffect = Toolkit::CreateDissolveEffect(mUseHighPrecision);
238   mNextImageEffect = Toolkit::CreateDissolveEffect(mUseHighPrecision);
239
240   mViewTimer = Timer::New( VIEWINGTIME );
241   mViewTimer.TickSignal().Connect( this, &DissolveEffectApp::OnTimerTick );
242   mTimerReady = true;
243
244   // Set size to stage size to avoid seeing a black border on transition
245   mParent = Actor::New();
246   mParent.SetSize( Stage::GetCurrent().GetSize() );
247   mParent.SetPositionInheritanceMode( USE_PARENT_POSITION );
248   mContent.Add( mParent );
249
250   // show the first image
251   mCurrentImage = ImageActor::New( LoadStageFillingImage( IMAGES[mIndex] ) );
252   mCurrentImage.SetPositionInheritanceMode(USE_PARENT_POSITION_PLUS_LOCAL_POSITION);
253   mCurrentImage.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS );
254   mCurrentImage.SetSizeScalePolicy( SizeScalePolicy::FIT_WITH_ASPECT_RATIO );
255   mParent.Add( mCurrentImage );
256
257   mPanGestureDetector.Attach( mCurrentImage );
258 }
259
260 // signal handler, called when the pan gesture is detected
261 void DissolveEffectApp::OnPanGesture( Actor actor, const PanGesture& gesture )
262 {
263   // does not response when the animation has not finished
264   if( mIsTransiting || mSlideshow )
265   {
266     return;
267   }
268
269   if( gesture.state == Gesture::Continuing )
270   {
271     if( gesture.displacement.x < 0)
272     {
273       mIndex = (mIndex + 1)%NUM_IMAGES;
274     }
275     else
276     {
277       mIndex = (mIndex + NUM_IMAGES -1)%NUM_IMAGES;
278     }
279
280     Image image = LoadStageFillingImage( IMAGES[ mIndex ] );
281     mNextImage = ImageActor::New( image );
282     mNextImage.SetPositionInheritanceMode(USE_PARENT_POSITION_PLUS_LOCAL_POSITION);
283     mNextImage.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS );
284     mNextImage.SetSizeScalePolicy( SizeScalePolicy::FIT_WITH_ASPECT_RATIO );
285     mNextImage.SetZ(INITIAL_DEPTH);
286     mParent.Add( mNextImage );
287     Vector2 size = Vector2( mCurrentImage.GetCurrentSize() );
288     StartTransition( gesture.position / size, gesture.displacement * Vector2(1.0, size.x/size.y));
289   }
290 }
291
292 void DissolveEffectApp::StartTransition(Vector2 position, Vector2 displacement)
293 {
294   mAnimation = Animation::New(TRANSITION_DURATION);
295
296   Dali::Toolkit::DissolveEffectSetCentralLine( mCurrentImageEffect, position, displacement );
297   mCurrentImageEffect.SetUniform("uPercentage", 0.0f);
298   mCurrentImage.SetShaderEffect(mCurrentImageEffect);
299   mAnimation.AnimateTo( Property(mCurrentImageEffect, "uPercentage"), 1.0f, AlphaFunction::LINEAR );
300
301   mNextImage.SetOpacity(0.0f);
302   mAnimation.AnimateTo( Property( mNextImage, Actor::Property::COLOR_ALPHA ), 1.0f, AlphaFunction::LINEAR );
303
304   if(mUseHighPrecision)
305   {
306     Dali::Toolkit::DissolveEffectSetCentralLine( mNextImageEffect, position, displacement );
307     mNextImageEffect.SetUniform("uPercentage", 1.0f);
308     mNextImage.SetShaderEffect(mNextImageEffect);
309     mAnimation.AnimateTo( Property(mNextImageEffect, "uPercentage"), 0.0f, AlphaFunction::LINEAR );
310   }
311   else
312   {
313     mAnimation.AnimateTo( Property( mNextImage, Actor::Property::POSITION ), Vector3( 0.0f, 0.0f, 0.0f ), AlphaFunction::LINEAR );
314   }
315
316   mAnimation.FinishedSignal().Connect( this, &DissolveEffectApp::OnTransitionCompleted );
317   mAnimation.Play();
318   mIsTransiting = true;
319 }
320
321 void DissolveEffectApp::OnKeyEvent(const KeyEvent& event)
322 {
323   if(event.state == KeyEvent::Down)
324   {
325     if( IsKey( event, Dali::DALI_KEY_ESCAPE) || IsKey( event, Dali::DALI_KEY_BACK) )
326     {
327       mApplication.Quit();
328     }
329   }
330 }
331
332 bool DissolveEffectApp::OnEffectButtonClicked( Toolkit::Button button )
333 {
334   mUseHighPrecision = !mUseHighPrecision;
335   mCurrentImageEffect = Dali::Toolkit::CreateDissolveEffect(mUseHighPrecision);
336   if(mUseHighPrecision)
337   {
338     mTitleActor.SetProperty( TextLabel::Property::TEXT, std::string(APPLICATION_TITLE_HIGHP) );
339     mEffectChangeButton.SetBackgroundImage(mIconHighP);
340   }
341   else
342   {
343     mTitleActor.SetProperty( TextLabel::Property::TEXT, std::string(APPLICATION_TITLE_MEDIUMP) );
344     mEffectChangeButton.SetBackgroundImage(mIconMediumP);
345   }
346
347   return true;
348 }
349
350 bool DissolveEffectApp::OnSildeshowButtonClicked( Toolkit::Button button )
351 {
352   mSlideshow = !mSlideshow;
353   if( mSlideshow )
354   {
355     mPlayStopButton.SetBackgroundImage( mIconStop );
356     mPanGestureDetector.Detach( mParent );
357     mViewTimer.Start();
358     mTimerReady = false;
359   }
360   else
361   {
362     mPlayStopButton.SetBackgroundImage( mIconPlay );
363     mTimerReady = true;
364     mPanGestureDetector.Attach( mParent );
365   }
366   return true;
367 }
368
369 void DissolveEffectApp::OnTransitionCompleted( Animation& source )
370 {
371   mCurrentImage.RemoveShaderEffect();
372   mNextImage.RemoveShaderEffect();
373   mParent.Remove( mCurrentImage );
374   mPanGestureDetector.Detach( mCurrentImage );
375   mCurrentImage = mNextImage;
376   mPanGestureDetector.Attach( mCurrentImage );
377   mIsTransiting = false;
378
379   if( mSlideshow)
380   {
381     mViewTimer.Start();
382     mTimerReady = false;
383   }
384 }
385
386 bool DissolveEffectApp::OnTimerTick()
387 {
388   mTimerReady = true;
389   if(mSlideshow)
390   {
391     mIndex = (mIndex + 1)%NUM_IMAGES;
392     Image image = LoadStageFillingImage( IMAGES[ mIndex ] );
393     mNextImage = ImageActor::New( image );
394     mNextImage.SetPositionInheritanceMode(USE_PARENT_POSITION_PLUS_LOCAL_POSITION);
395     mNextImage.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS );
396     mNextImage.SetSizeScalePolicy( SizeScalePolicy::FIT_WITH_ASPECT_RATIO );
397     mNextImage.SetZ(INITIAL_DEPTH);
398     mParent.Add( mNextImage );
399     switch( mCentralLineIndex%4 )
400     {
401       case 0:
402       {
403         StartTransition(Vector2(1.0f,0.5f), Vector2(-1.0f, 0.0f));
404         break;
405       }
406       case 1:
407       {
408         StartTransition(Vector2(0.5f,0.0f), Vector2(0.0f, 1.0f));
409         break;
410       }
411       case 2:
412       {
413         StartTransition(Vector2(0.0f,0.5f), Vector2(1.0f, 0.0f));
414         break;
415       }
416       default:
417       {
418         StartTransition(Vector2(0.5f,1.0f), Vector2(0.0f, -1.0f));
419         break;
420       }
421
422     }
423     mCentralLineIndex++;
424   }
425   return false;   //return false to stop the timer
426 }
427
428 // Entry point for Linux & Tizen applications
429 int main( int argc, char **argv )
430 {
431   Application application = Application::New( &argc, &argv, DALI_DEMO_THEME_PATH );
432   DissolveEffectApp test( application );
433   application.MainLoop();
434
435   return 0;
436 }