Move more public-api headers to devel-api. PART 3
[platform/core/uifw/dali-demo.git] / examples / motion-blur / motion-blur-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 #include <sstream>
19 #include <iomanip>
20
21 #include "shared/view.h"
22 #include <dali/dali.h>
23 #include <dali-toolkit/dali-toolkit.h>
24 #include <dali-toolkit/devel-api/shader-effects/motion-blur-effect.h>
25 #include <dali-toolkit/devel-api/controls/popup/popup.h>
26
27 using namespace Dali;
28 using namespace Dali::Toolkit;
29
30
31
32 namespace // unnamed namespace
33 {
34
35 ////////////////////////////////////////////////////
36 //
37 // Demo setup parameters
38 //
39
40 //#define MULTIPLE_MOTION_BLURRED_ACTORS
41 #ifndef MULTIPLE_MOTION_BLURRED_ACTORS
42
43 const float MOTION_BLUR_ACTOR_WIDTH = 256;                                          // actor size on screen
44 const float MOTION_BLUR_ACTOR_HEIGHT = 256;                                         // ""
45
46 #else //#ifndef MULTIPLE_MOTION_BLURRED_ACTORS
47
48 const float MOTION_BLUR_ACTOR_WIDTH = 150;                                          // actor size on screen
49 const float MOTION_BLUR_ACTOR_HEIGHT = 112;                                         // ""
50
51 #endif //#ifndef MULTIPLE_MOTION_BLURRED_ACTORS
52
53
54 const unsigned int MOTION_BLUR_NUM_SAMPLES = 8;
55
56 const int MOTION_BLUR_NUM_ACTOR_IMAGES = 5;
57 const char* MOTION_BLUR_ACTOR_IMAGE1( DALI_IMAGE_DIR "image-with-border-1.jpg" );
58 const char* MOTION_BLUR_ACTOR_IMAGE2( DALI_IMAGE_DIR "image-with-border-2.jpg" );
59 const char* MOTION_BLUR_ACTOR_IMAGE3( DALI_IMAGE_DIR "image-with-border-3.jpg" );
60 const char* MOTION_BLUR_ACTOR_IMAGE4( DALI_IMAGE_DIR "image-with-border-4.jpg" );
61 const char* MOTION_BLUR_ACTOR_IMAGE5( DALI_IMAGE_DIR "image-with-border-1.jpg" );
62
63 const char* MOTION_BLUR_ACTOR_IMAGES[] = {
64   MOTION_BLUR_ACTOR_IMAGE1,
65   MOTION_BLUR_ACTOR_IMAGE2,
66   MOTION_BLUR_ACTOR_IMAGE3,
67   MOTION_BLUR_ACTOR_IMAGE4,
68   MOTION_BLUR_ACTOR_IMAGE5,
69 };
70
71 const int NUM_ACTOR_ANIMATIONS = 4;
72 const int NUM_CAMERA_ANIMATIONS = 2;
73
74
75 const char* BACKGROUND_IMAGE_PATH = DALI_IMAGE_DIR "background-default.png";
76
77 const char* TOOLBAR_IMAGE( DALI_IMAGE_DIR "top-bar.png" );
78 const char* LAYOUT_IMAGE( DALI_IMAGE_DIR "icon-change.png" );
79 const char* APPLICATION_TITLE( "Motion Blur" );
80 const char* EFFECTS_OFF_ICON( DALI_IMAGE_DIR "icon-effects-off.png" );
81 const char* EFFECTS_ON_ICON( DALI_IMAGE_DIR "icon-effects-on.png" );
82
83 const float UI_MARGIN = 4.0f;                              ///< Screen Margin for placement of UI buttons
84
85 const Vector3 BUTTON_SIZE_CONSTRAINT( 0.24f, 0.09f, 1.0f );
86 const Vector3 BUTTON_TITLE_LABEL_TAP_HERE_SIZE_CONSTRAINT( 0.55f, 0.06f, 1.0f );
87 const Vector3 BUTTON_TITLE_LABEL_INSTRUCTIONS_POPUP_SIZE_CONSTRAINT( 1.0f, 1.0f, 1.0f );
88
89 // move this button down a bit so it is visible on target and not covered up by toolbar
90 const float BUTTON_TITLE_LABEL_Y_OFFSET = 0.05f;
91
92 const float ORIENTATION_DURATION = 0.5f;                  ///< Time to rotate to new orientation.
93
94 /**
95  * @brief Load an image, scaled-down to no more than the dimensions passed in.
96  *
97  * Uses SHRINK_TO_FIT which ensures the resulting image is
98  * smaller than or equal to the specified dimensions while preserving its
99  * original aspect ratio.
100  */
101 ResourceImage LoadImageFittedInBox( const char * const imagePath, uint32_t maxWidth, uint32_t maxHeight )
102 {
103   // Load the image nicely scaled-down to fit within the specified max width and height:
104   return ResourceImage::New( imagePath, ImageDimensions( maxWidth, maxHeight ), FittingMode::SHRINK_TO_FIT, Dali::SamplingMode::BOX_THEN_LINEAR );
105 }
106
107 } // unnamed namespace
108
109
110 //
111 class MotionBlurExampleApp : public ConnectionTracker
112 {
113 public:
114
115   /**
116      * DeviceOrientation describes the four different
117      * orientations the device can be in based on accelerometer reports.
118      */
119   enum DeviceOrientation
120   {
121     PORTRAIT = 0,
122     LANDSCAPE = 90,
123     PORTRAIT_INVERSE = 180,
124     LANDSCAPE_INVERSE = 270
125   };
126
127   /**
128    * Constructor
129    * @param application class, stored as reference
130    */
131   MotionBlurExampleApp(Application &app)
132   : mApplication(app),
133     mActorEffectsEnabled(false),
134     mCurrentActorAnimation(0),
135     mCurrentImage(0)
136   {
137     // Connect to the Application's Init signal
138     app.InitSignal().Connect(this, &MotionBlurExampleApp::OnInit);
139   }
140
141   ~MotionBlurExampleApp()
142   {
143     // Nothing to do here; everything gets deleted automatically
144   }
145
146   /**
147    * This method gets called once the main loop of application is up and running
148    */
149   void OnInit(Application& app)
150   {
151     // The Init signal is received once (only) during the Application lifetime
152
153     Stage::GetCurrent().KeyEventSignal().Connect(this, &MotionBlurExampleApp::OnKeyEvent);
154
155
156     // Creates a default view with a default tool bar.
157     // The view is added to the stage.
158     mContentLayer = DemoHelper::CreateView( mApplication,
159                                             mView,
160                                             mToolBar,
161                                             BACKGROUND_IMAGE_PATH,
162                                             TOOLBAR_IMAGE,
163                                             APPLICATION_TITLE );
164
165     //Add an effects icon on the right of the title
166     mIconEffectsOff = ResourceImage::New( EFFECTS_OFF_ICON );
167     mIconEffectsOn = ResourceImage::New( EFFECTS_ON_ICON );
168     mActorEffectsButton = Toolkit::PushButton::New();
169     mActorEffectsButton.SetBackgroundImage( mIconEffectsOff );
170     mActorEffectsButton.ClickedSignal().Connect( this, &MotionBlurExampleApp::OnEffectButtonClicked );
171     mToolBar.AddControl( mActorEffectsButton, DemoHelper::DEFAULT_VIEW_STYLE.mToolBarButtonPercentage, Toolkit::Alignment::HorizontalCenter, DemoHelper::DEFAULT_PLAY_PADDING );
172
173     // Creates a mode button.
174     // Create a effect toggle button. (right of toolbar)
175     Image imageLayout = ResourceImage::New( LAYOUT_IMAGE );
176     Toolkit::PushButton layoutButton = Toolkit::PushButton::New();
177     layoutButton.SetBackgroundImage(imageLayout);
178     layoutButton.ClickedSignal().Connect( this, &MotionBlurExampleApp::OnLayoutButtonClicked);
179     layoutButton.SetLeaveRequired( true );
180     mToolBar.AddControl( layoutButton, DemoHelper::DEFAULT_VIEW_STYLE.mToolBarButtonPercentage, Toolkit::Alignment::HorizontalRight, DemoHelper::DEFAULT_MODE_SWITCH_PADDING );
181
182     // Input
183     mTapGestureDetector = TapGestureDetector::New();
184     mTapGestureDetector.Attach( mContentLayer );
185     mTapGestureDetector.DetectedSignal().Connect( this, &MotionBlurExampleApp::OnTap );
186
187     Dali::Window winHandle = app.GetWindow();
188     winHandle.AddAvailableOrientation( Dali::Window::PORTRAIT );
189     winHandle.AddAvailableOrientation( Dali::Window::LANDSCAPE );
190     winHandle.AddAvailableOrientation( Dali::Window::PORTRAIT_INVERSE  );
191     winHandle.AddAvailableOrientation( Dali::Window::LANDSCAPE_INVERSE );
192
193     // set initial orientation
194     winHandle.GetOrientation().ChangedSignal().Connect( this, &MotionBlurExampleApp::OnOrientationChanged );
195     unsigned int degrees = winHandle.GetOrientation().GetDegrees();
196     Rotate( static_cast< DeviceOrientation >( degrees ) );
197
198
199     ///////////////////////////////////////////////////////
200     //
201     // Motion blurred actor
202     //
203
204     // Scale down actor to fit on very low resolution screens with space to interact:
205     Size stageSize = Stage::GetCurrent().GetSize();
206     mMotionBlurActorSize = Size( std::min( stageSize.x * 0.3f, MOTION_BLUR_ACTOR_WIDTH ), std::min( stageSize.y * 0.3f, MOTION_BLUR_ACTOR_HEIGHT ) );
207     mMotionBlurActorSize = Size( std::min( mMotionBlurActorSize.x, mMotionBlurActorSize.y ), std::min( mMotionBlurActorSize.x, mMotionBlurActorSize.y ) );
208
209     Image image = LoadImageFittedInBox( MOTION_BLUR_ACTOR_IMAGE1, mMotionBlurActorSize.x, mMotionBlurActorSize.y );
210     mMotionBlurImageActor = ImageActor::New(image);
211     mMotionBlurImageActor.SetParentOrigin( ParentOrigin::CENTER );
212     mMotionBlurImageActor.SetSize(mMotionBlurActorSize.x, mMotionBlurActorSize.y);
213
214     mContentLayer.Add( mMotionBlurImageActor );
215
216     // Create shader used for doing motion blur
217     mMotionBlurEffect = MotionBlurEffect::Apply(mMotionBlurImageActor);
218
219
220 #ifdef MULTIPLE_MOTION_BLURRED_ACTORS
221
222     ///////////////////////////////////////////////////////
223     //
224     // Motion blurred actor 2
225     //
226
227     mMotionBlurImageActor2 = ImageActor::New(image);
228     mMotionBlurImageActor2.SetParentOrigin( ParentOrigin::CENTER );
229     mMotionBlurImageActor2.SetSize(mMotionBlurActorSize.x, mMotionBlurActorSize.y);
230     mMotionBlurImageActor2.SetPosition(mMotionBlurActorSize.x * 1.1f, 0.0f);
231     mMotionBlurImageActor.Add( mMotionBlurImageActor2 );
232
233     // Create shader used for doing motion blur
234     mMotionBlurEffect2 = MotionBlurEffect::New(MOTION_BLUR_NUM_SAMPLES);
235
236     // set actor shader to the blur one
237     mMotionBlurImageActor2.SetShaderEffect( mMotionBlurEffect2 );
238
239
240     ///////////////////////////////////////////////////////
241     //
242     // Motion blurred actor 3
243     //
244
245     mMotionBlurImageActor3 = ImageActor::New(image);
246     mMotionBlurImageActor3.SetParentOrigin( ParentOrigin::CENTER );
247     mMotionBlurImageActor3.SetSize(mMotionBlurActorSize.x, mMotionBlurActorSize.y);
248     mMotionBlurImageActor3.SetPosition(-mMotionBlurActorSize.x * 1.1f, 0.0f);
249     mMotionBlurImageActor.Add( mMotionBlurImageActor3 );
250
251     // Create shader used for doing motion blur
252     mMotionBlurEffect3 = MotionBlurEffect::New(MOTION_BLUR_NUM_SAMPLES);
253
254     // set actor shader to the blur one
255     mMotionBlurImageActor3.SetShaderEffect( mMotionBlurEffect3 );
256
257
258     ///////////////////////////////////////////////////////
259     //
260     // Motion blurred actor 4
261     //
262
263     mMotionBlurImageActor4 = ImageActor::New(image);
264     mMotionBlurImageActor4.SetParentOrigin( ParentOrigin::CENTER );
265     mMotionBlurImageActor4.SetSize(mMotionBlurActorSize.x, mMotionBlurActorSize.y);
266     mMotionBlurImageActor4.SetPosition(0.0f, mMotionBlurActorSize.y * 1.1f);
267     mMotionBlurImageActor.Add( mMotionBlurImageActor4 );
268
269     // Create shader used for doing motion blur
270     mMotionBlurEffect4 = MotionBlurEffect::New(MOTION_BLUR_NUM_SAMPLES);
271
272     // set actor shader to the blur one
273     mMotionBlurImageActor4.SetShaderEffect( mMotionBlurEffect4 );
274
275
276     ///////////////////////////////////////////////////////
277     //
278     // Motion blurred actor 5
279     //
280
281     mMotionBlurImageActor5 = ImageActor::New(image);
282     mMotionBlurImageActor5.SetParentOrigin( ParentOrigin::CENTER );
283     mMotionBlurImageActor5.SetSize(mMotionBlurActorSize.x, mMotionBlurActorSize.y);
284     mMotionBlurImageActor5.SetPosition(0.0f, -mMotionBlurActorSize.y * 1.1f);
285     mMotionBlurImageActor.Add( mMotionBlurImageActor5 );
286
287     // Create shader used for doing motion blur
288     mMotionBlurEffect5 = MotionBlurEffect::New(MOTION_BLUR_NUM_SAMPLES);
289
290     // set actor shader to the blur one
291     mMotionBlurImageActor5.SetShaderEffect( mMotionBlurEffect5 );
292 #endif //#ifdef MULTIPLE_MOTION_BLURRED_ACTORS
293   }
294
295   //////////////////////////////////////////////////////////////
296   //
297   // Device Orientation Support
298   //
299   //
300
301   void OnOrientationChanged( Orientation orientation )
302   {
303     unsigned int degrees = orientation.GetDegrees();
304     Rotate( static_cast< DeviceOrientation >( degrees ) );
305   }
306
307   void Rotate( DeviceOrientation orientation )
308   {
309     // Resize the root actor
310     Vector2 stageSize = Stage::GetCurrent().GetSize();
311     Vector2 targetSize = stageSize;
312     if( orientation == LANDSCAPE ||
313         orientation == LANDSCAPE_INVERSE )
314     {
315       targetSize = Vector2( stageSize.y, stageSize.x );
316     }
317
318     if( mOrientation != orientation )
319     {
320       mOrientation = orientation;
321
322       // check if actor is on stage
323       if( mView.GetParent() )
324       {
325         // has parent so we expect it to be on stage, start animation
326         mRotateAnimation = Animation::New( ORIENTATION_DURATION );
327         mRotateAnimation.AnimateTo( Property( mView, Actor::Property::ORIENTATION ), Quaternion( Radian( Degree( -orientation ) ), Vector3::ZAXIS ), AlphaFunction::EASE_OUT );
328         mRotateAnimation.AnimateTo( Property( mView, Actor::Property::SIZE_WIDTH ), targetSize.width );
329         mRotateAnimation.AnimateTo( Property( mView, Actor::Property::SIZE_HEIGHT ), targetSize.height );
330         mRotateAnimation.Play();
331       }
332       else
333       {
334         // set the rotation to match the orientation
335         mView.SetOrientation( Degree( -orientation ), Vector3::ZAXIS );
336         mView.SetSize( targetSize );
337       }
338     }
339     else
340     {
341       // for first time just set size
342       mView.SetSize( targetSize );
343     }
344   }
345
346
347   //////////////////////////////////////////////////////////////
348   //
349   // Actor Animation
350   //
351   //
352
353   // move to point on screen that was tapped
354   void OnTap( Actor actor, const TapGesture& tapGesture )
355   {
356     Vector3 destPos;
357     float originOffsetX, originOffsetY;
358
359     // rotate offset (from top left origin to centre) into actor space
360     Vector2 stageSize = Dali::Stage::GetCurrent().GetSize();
361     actor.ScreenToLocal(originOffsetX, originOffsetY, stageSize.width * 0.5f, stageSize.height * 0.5f);
362
363     // get dest point in local actor space
364     destPos.x = tapGesture.localPoint.x - originOffsetX;
365     destPos.y = tapGesture.localPoint.y - originOffsetY;
366     destPos.z = 0.0f;
367
368     float animDuration = 0.5f;
369     mActorTapMovementAnimation = Animation::New( animDuration );
370     if ( mMotionBlurImageActor )
371     {
372       mActorTapMovementAnimation.AnimateTo( Property(mMotionBlurImageActor, Actor::Property::POSITION), destPos, AlphaFunction::EASE_IN_OUT_SINE, TimePeriod(animDuration) );
373     }
374     mActorTapMovementAnimation.SetEndAction( Animation::Bake );
375     mActorTapMovementAnimation.Play();
376
377
378     // perform some spinning etc
379     if(mActorEffectsEnabled)
380     {
381       switch(mCurrentActorAnimation)
382       {
383         // spin around y
384         case 0:
385         {
386           float animDuration = 1.0f;
387           mActorAnimation = Animation::New(animDuration);
388           mActorAnimation.AnimateBy( Property( mMotionBlurImageActor, Actor::Property::ORIENTATION ), Quaternion( Radian( Degree(360.0f) ), Vector3::YAXIS ), AlphaFunction::EASE_IN_OUT );
389           mActorAnimation.SetEndAction( Animation::Bake );
390           mActorAnimation.Play();
391         }
392         break;
393
394         // spin around z
395         case 1:
396         {
397           float animDuration = 1.0f;
398           mActorAnimation = Animation::New(animDuration);
399           mActorAnimation.AnimateBy( Property( mMotionBlurImageActor, Actor::Property::ORIENTATION ), Quaternion( Radian( Degree(360.0f) ), Vector3::ZAXIS ), AlphaFunction::EASE_IN_OUT );
400           mActorAnimation.SetEndAction( Animation::Bake );
401           mActorAnimation.Play();
402         }
403         break;
404
405         // spin around y and z
406         case 2:
407         {
408           float animDuration = 1.0f;
409           mActorAnimation = Animation::New(animDuration);
410           mActorAnimation.AnimateBy( Property( mMotionBlurImageActor, Actor::Property::ORIENTATION ), Quaternion( Radian( Degree(360.0f) ), Vector3::YAXIS ), AlphaFunction::EASE_IN_OUT );
411           mActorAnimation.AnimateBy( Property( mMotionBlurImageActor, Actor::Property::ORIENTATION ), Quaternion( Radian( Degree(360.0f) ), Vector3::ZAXIS ), AlphaFunction::EASE_IN_OUT );
412           mActorAnimation.SetEndAction( Animation::Bake );
413           mActorAnimation.Play();
414         }
415         break;
416
417         // scale
418         case 3:
419         {
420           float animDuration = 1.0f;
421           mActorAnimation = Animation::New(animDuration);
422           mActorAnimation.AnimateBy( Property( mMotionBlurImageActor, Actor::Property::SCALE ), Vector3(2.0f, 2.0f, 2.0f), AlphaFunction::BOUNCE, TimePeriod( 0.0f, 1.0f ) );
423           mActorAnimation.SetEndAction( Animation::Bake );
424           mActorAnimation.Play();
425         }
426         break;
427
428         default:
429           break;
430       }
431
432       mCurrentActorAnimation++;
433       if(NUM_ACTOR_ANIMATIONS == mCurrentActorAnimation)
434       {
435         mCurrentActorAnimation = 0;
436       }
437     }
438   }
439
440   void ToggleActorEffects()
441   {
442     if(!mActorEffectsEnabled)
443     {
444       mActorEffectsEnabled = true;
445       mActorEffectsButton.SetBackgroundImage( mIconEffectsOn );
446     }
447     else
448     {
449       mActorEffectsEnabled = false;
450       mActorEffectsButton.SetBackgroundImage( mIconEffectsOff );
451     }
452   }
453
454   //////////////////////////////////////////////////////////////
455   //
456   // Input handlers
457   //
458   //
459
460   bool OnLayoutButtonClicked( Toolkit::Button button )
461   {
462     ChangeImage();
463     return true;
464   }
465
466   bool OnEffectButtonClicked( Toolkit::Button button )
467   {
468     ToggleActorEffects();
469     return true;
470   }
471
472   /**
473    * Main key event handler
474    */
475   void OnKeyEvent(const KeyEvent& event)
476   {
477     if(event.state == KeyEvent::Down)
478     {
479       if( IsKey( event, Dali::DALI_KEY_ESCAPE) || IsKey( event, Dali::DALI_KEY_BACK) )
480       {
481         mApplication.Quit();
482       }
483     }
484   }
485
486   //////////////////////////////////////////////////////////////
487   //
488   // Misc
489   //
490   //
491
492
493   void ChangeImage()
494   {
495     mCurrentImage++;
496     if(MOTION_BLUR_NUM_ACTOR_IMAGES == mCurrentImage)
497     {
498       mCurrentImage = 0;
499     }
500
501     Image blurImage = LoadImageFittedInBox( MOTION_BLUR_ACTOR_IMAGES[mCurrentImage], mMotionBlurActorSize.x, mMotionBlurActorSize.y );
502     mMotionBlurImageActor.SetImage(blurImage);
503   }
504
505
506 private:
507   Application&               mApplication;            ///< Application instance
508   Toolkit::Control           mView;
509   Toolkit::ToolBar           mToolBar;
510   Image                      mIconEffectsOff;
511   Image                      mIconEffectsOn;
512
513   Layer                      mContentLayer;           ///< Content layer (contains actor for this blur demo)
514
515   PushButton                 mActorEffectsButton;     ///< The actor effects toggling Button.
516
517   // Motion blur
518   MotionBlurEffect mMotionBlurEffect;
519   ImageActor mMotionBlurImageActor;
520   Size mMotionBlurActorSize;
521
522 #ifdef MULTIPLE_MOTION_BLURRED_ACTORS
523   MotionBlurEffect mMotionBlurEffect2;
524   MotionBlurEffect mMotionBlurEffect3;
525   MotionBlurEffect mMotionBlurEffect4;
526   MotionBlurEffect mMotionBlurEffect5;
527
528   ImageActor mMotionBlurImageActor2;
529   ImageActor mMotionBlurImageActor3;
530   ImageActor mMotionBlurImageActor4;
531   ImageActor mMotionBlurImageActor5;
532 #endif //#ifdef MULTIPLE_MOTION_BLURRED_ACTORS
533
534   // animate actor to position where user taps screen
535   Animation mActorTapMovementAnimation;
536
537   // show different animations to demonstrate blur effect working on an object only movement basis
538   bool mActorEffectsEnabled;
539   Animation mActorAnimation;
540   int mCurrentActorAnimation;
541
542   // offer a selection of images that user can cycle between
543   int mCurrentImage;
544
545   TapGestureDetector mTapGestureDetector;
546
547   DeviceOrientation mOrientation;               ///< Current Device orientation
548   Animation mRotateAnimation;                   ///< Animation for rotating between landscape and portrait.
549
550   Popup mInstructionsPopup;                     ///< Info Popup
551 };
552
553 void RunTest(Application& app)
554 {
555   MotionBlurExampleApp test(app);
556
557   app.MainLoop();
558 }
559
560 // Entry point for Linux & Tizen applications
561 //
562 int main(int argc, char **argv)
563 {
564   Application app = Application::New(&argc, &argv);
565
566   RunTest(app);
567
568   return 0;
569 }