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