ShaderEffect changes
[platform/core/uifw/dali-demo.git] / examples / motion-stretch / motion-stretch-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 const float MOTION_STRETCH_ACTOR_WIDTH = 256;                                          // actor size on screen
39 const float MOTION_STRETCH_ACTOR_HEIGHT = 256;                                         // ""
40
41 const int MOTION_STRETCH_NUM_ACTOR_IMAGES = 5;
42 const char* MOTION_STRETCH_ACTOR_IMAGE1( DALI_IMAGE_DIR "image-with-border-1.jpg" );
43 const char* MOTION_STRETCH_ACTOR_IMAGE2( DALI_IMAGE_DIR "image-with-border-2.jpg" );
44 const char* MOTION_STRETCH_ACTOR_IMAGE3( DALI_IMAGE_DIR "image-with-border-3.jpg" );
45 const char* MOTION_STRETCH_ACTOR_IMAGE4( DALI_IMAGE_DIR "image-with-border-4.jpg" );
46 const char* MOTION_STRETCH_ACTOR_IMAGE5( DALI_IMAGE_DIR "image-with-border-5.jpg" );
47
48 const char* MOTION_STRETCH_ACTOR_IMAGES[] = {
49   MOTION_STRETCH_ACTOR_IMAGE1,
50   MOTION_STRETCH_ACTOR_IMAGE2,
51   MOTION_STRETCH_ACTOR_IMAGE3,
52   MOTION_STRETCH_ACTOR_IMAGE4,
53   MOTION_STRETCH_ACTOR_IMAGE5,
54 };
55
56 const int NUM_ACTOR_ANIMATIONS = 4;
57 const int NUM_CAMERA_ANIMATIONS = 2;
58
59
60 const char* BACKGROUND_IMAGE_PATH = DALI_IMAGE_DIR "background-default.png";
61
62 const char* TOOLBAR_IMAGE( DALI_IMAGE_DIR "top-bar.png" );
63 const char* LAYOUT_IMAGE( DALI_IMAGE_DIR "icon-change.png" );
64 const char* APPLICATION_TITLE( "Motion Stretch" );
65 const char* EFFECTS_OFF_ICON( DALI_IMAGE_DIR "icon-effects-off.png" );
66 const char* EFFECTS_ON_ICON( DALI_IMAGE_DIR "icon-effects-on.png" );
67
68 // These values depend on the button background image
69 const Vector4 BUTTON_IMAGE_BORDER( Vector4::ONE * 3.0f );
70
71 const float UI_MARGIN = 4.0f;                              ///< Screen Margin for placement of UI buttons
72
73 const Vector3 BUTTON_SIZE_CONSTRAINT( 0.24f, 0.09f, 1.0f );
74
75 // move this button down a bit so it is visible on target and not covered up by toolbar
76 const float BUTTON_TITLE_LABEL_Y_OFFSET = 0.05f;
77
78 const float ORIENTATION_DURATION = 0.5f;                  ///< Time to rotate to new orientation.
79 } // unnamed namespace
80
81
82
83
84 //
85 class MotionStretchExampleApp : public ConnectionTracker
86 {
87 public:
88
89   /**
90      * DeviceOrientation describes the four different
91      * orientations the device can be in based on accelerometer reports.
92      */
93   enum DeviceOrientation
94   {
95     PORTRAIT = 0,
96     LANDSCAPE = 90,
97     PORTRAIT_INVERSE = 180,
98     LANDSCAPE_INVERSE = 270
99   };
100
101   /**
102    * Constructor
103    * @param application class, stored as reference
104    */
105   MotionStretchExampleApp(Application &app)
106   : mApplication(app),
107     mActorEffectsEnabled(false),
108     mCurrentActorAnimation(0),
109     mCurrentImage(0)
110   {
111     // Connect to the Application's Init signal
112     app.InitSignal().Connect(this, &MotionStretchExampleApp::OnInit);
113   }
114
115   ~MotionStretchExampleApp()
116   {
117     // Nothing to do here; everything gets deleted automatically
118   }
119
120   /**
121    * This method gets called once the main loop of application is up and running
122    */
123   void OnInit(Application& app)
124   {
125     // The Init signal is received once (only) during the Application lifetime
126
127     DemoHelper::RequestThemeChange();
128
129     Stage::GetCurrent().KeyEventSignal().Connect(this, &MotionStretchExampleApp::OnKeyEvent);
130
131     // Creates a default view with a default tool bar.
132     // The view is added to the stage.
133     mContentLayer = DemoHelper::CreateView( mApplication,
134                                             mView,
135                                             mToolBar,
136                                             BACKGROUND_IMAGE_PATH,
137                                             TOOLBAR_IMAGE,
138                                             APPLICATION_TITLE );
139
140     //Add an slideshow icon on the right of the title
141     mIconEffectsOff = ResourceImage::New( EFFECTS_OFF_ICON );
142     mIconEffectsOn = ResourceImage::New( EFFECTS_ON_ICON );
143     mActorEffectsButton = Toolkit::PushButton::New();
144     mActorEffectsButton.SetBackgroundImage( mIconEffectsOff );
145     mActorEffectsButton.ClickedSignal().Connect( this, &MotionStretchExampleApp::OnEffectButtonClicked );
146     mToolBar.AddControl( mActorEffectsButton, DemoHelper::DEFAULT_VIEW_STYLE.mToolBarButtonPercentage, Toolkit::Alignment::HorizontalCenter, DemoHelper::DEFAULT_PLAY_PADDING );
147
148     // Creates a mode button.
149     // Create a effect toggle button. (right of toolbar)
150     Image imageLayout = ResourceImage::New( LAYOUT_IMAGE );
151     Toolkit::PushButton layoutButton = Toolkit::PushButton::New();
152     layoutButton.SetBackgroundImage(imageLayout);
153     layoutButton.ClickedSignal().Connect( this, &MotionStretchExampleApp::OnLayoutButtonClicked);
154     layoutButton.SetLeaveRequired( true );
155     mToolBar.AddControl( layoutButton, DemoHelper::DEFAULT_VIEW_STYLE.mToolBarButtonPercentage, Toolkit::Alignment::HorizontalRight, DemoHelper::DEFAULT_MODE_SWITCH_PADDING );
156
157     // Input
158     mTapGestureDetector = TapGestureDetector::New();
159     mTapGestureDetector.Attach( mContentLayer );
160     mTapGestureDetector.DetectedSignal().Connect( this, &MotionStretchExampleApp::OnTap );
161
162     // set initial orientation
163     Dali::Window winHandle = app.GetWindow();
164     winHandle.AddAvailableOrientation( Dali::Window::PORTRAIT );
165     winHandle.AddAvailableOrientation( Dali::Window::LANDSCAPE );
166     winHandle.AddAvailableOrientation( Dali::Window::PORTRAIT_INVERSE  );
167     winHandle.AddAvailableOrientation( Dali::Window::LANDSCAPE_INVERSE );
168
169     winHandle.GetOrientation().ChangedSignal().Connect( this, &MotionStretchExampleApp::OnOrientationChanged );
170     unsigned int degrees = winHandle.GetOrientation().GetDegrees();
171     Rotate( static_cast< DeviceOrientation >( degrees ) );
172
173
174     ///////////////////////////////////////////////////////
175     //
176     // Motion stretched actor
177     //
178
179     Image image = ResourceImage::New( MOTION_STRETCH_ACTOR_IMAGE1 );
180     mMotionStretchImageActor = ImageActor::New(image);
181     mMotionStretchImageActor.SetParentOrigin( ParentOrigin::CENTER );
182     mMotionStretchImageActor.SetAnchorPoint( AnchorPoint::CENTER );
183     mMotionStretchImageActor.SetSize(MOTION_STRETCH_ACTOR_WIDTH, MOTION_STRETCH_ACTOR_HEIGHT);
184
185     mContentLayer.Add( mMotionStretchImageActor );
186
187     // Create shader used for doing motion stretch
188     mMotionStretchEffect = Toolkit::CreateMotionStretchEffect();
189     Dali::Property::Index uModelProperty = mMotionStretchEffect.GetPropertyIndex( "uModelLastFrame" );
190     Constraint constraint = Constraint::New<Matrix>( mMotionStretchEffect, uModelProperty, EqualToConstraint() );
191     constraint.AddSource( Source( mMotionStretchImageActor , Actor::Property::WORLD_MATRIX ) );
192     constraint.Apply();
193     mMotionStretchImageActor.SetShaderEffect( mMotionStretchEffect );
194   }
195
196   //////////////////////////////////////////////////////////////
197   //
198   // Device Orientation Support
199   //
200   //
201
202   void OnOrientationChanged( Orientation orientation )
203   {
204     unsigned int degrees = orientation.GetDegrees();
205     Rotate( static_cast< DeviceOrientation >( degrees ) );
206   }
207
208   void Rotate( DeviceOrientation orientation )
209   {
210     // Resize the root actor
211     Vector2 stageSize = Stage::GetCurrent().GetSize();
212     Vector2 targetSize = stageSize;
213     if( orientation == LANDSCAPE ||
214         orientation == LANDSCAPE_INVERSE )
215     {
216       targetSize = Vector2( stageSize.y, stageSize.x );
217     }
218
219     if( mOrientation != orientation )
220     {
221       mOrientation = orientation;
222
223       // check if actor is on stage
224       if( mView.GetParent() )
225       {
226         // has parent so we expect it to be on stage, start animation
227         mRotateAnimation = Animation::New( ORIENTATION_DURATION );
228         mRotateAnimation.AnimateTo( Property( mView, Actor::Property::ORIENTATION ), Quaternion( Radian( Degree( -orientation ) ), Vector3::ZAXIS ), AlphaFunction::EASE_OUT );
229         mRotateAnimation.AnimateTo( Property( mView, Actor::Property::SIZE_WIDTH ), targetSize.width );
230         mRotateAnimation.AnimateTo( Property( mView, Actor::Property::SIZE_HEIGHT ), targetSize.height );
231         mRotateAnimation.Play();
232       }
233       else
234       {
235         // set the rotation to match the orientation
236         mView.SetOrientation( Degree( -orientation ), Vector3::ZAXIS );
237         mView.SetSize( targetSize );
238       }
239     }
240     else
241     {
242       // for first time just set size
243       mView.SetSize( targetSize );
244     }
245   }
246
247   //////////////////////////////////////////////////////////////
248   //
249   // Actor Animation
250   //
251   //
252
253   // move to point on screen that was tapped
254   void OnTap( Actor actor, const TapGesture& tapGesture )
255   {
256     Vector3 destPos;
257     float originOffsetX, originOffsetY;
258
259     // rotate offset (from top left origin to centre) into actor space
260     Vector2 stageSize = Dali::Stage::GetCurrent().GetSize();
261     actor.ScreenToLocal(originOffsetX, originOffsetY, stageSize.width * 0.5f, stageSize.height * 0.5f);
262
263     // get dest point in local actor space
264     destPos.x = tapGesture.localPoint.x - originOffsetX;
265     destPos.y = tapGesture.localPoint.y - originOffsetY;
266     destPos.z = 0.0f;
267
268     float animDuration = 0.5f;
269     mActorTapMovementAnimation = Animation::New( animDuration );
270     if ( mMotionStretchImageActor )
271     {
272       mActorTapMovementAnimation.AnimateTo( Property(mMotionStretchImageActor, Actor::Property::POSITION), destPos, AlphaFunction::EASE_IN_OUT_SINE, TimePeriod(animDuration) );
273     }
274     mActorTapMovementAnimation.SetEndAction( Animation::Bake );
275     mActorTapMovementAnimation.Play();
276
277
278     // perform some spinning etc
279     if(mActorEffectsEnabled)
280     {
281       switch(mCurrentActorAnimation)
282       {
283         // spin around y
284         case 0:
285         {
286           float animDuration = 1.0f;
287           mActorAnimation = Animation::New(animDuration);
288           mActorAnimation.AnimateBy( Property( mMotionStretchImageActor, Actor::Property::ORIENTATION ), Quaternion( Radian( Degree(360.0f) ), Vector3::YAXIS ), AlphaFunction::EASE_IN_OUT );
289           mActorAnimation.SetEndAction( Animation::Bake );
290           mActorAnimation.Play();
291         }
292         break;
293
294         // spin around z
295         case 1:
296         {
297           float animDuration = 1.0f;
298           mActorAnimation = Animation::New(animDuration);
299           mActorAnimation.AnimateBy( Property( mMotionStretchImageActor, Actor::Property::ORIENTATION ), Quaternion( Radian( Degree(360.0f) ), Vector3::ZAXIS ), AlphaFunction::EASE_IN_OUT );
300           mActorAnimation.SetEndAction( Animation::Bake );
301           mActorAnimation.Play();
302         }
303         break;
304
305         // spin around y and z
306         case 2:
307         {
308           float animDuration = 1.0f;
309           mActorAnimation = Animation::New(animDuration);
310           mActorAnimation.AnimateBy( Property( mMotionStretchImageActor, Actor::Property::ORIENTATION ), Quaternion( Radian( Degree(360.0f) ), Vector3::YAXIS ), AlphaFunction::EASE_IN_OUT );
311           mActorAnimation.AnimateBy( Property( mMotionStretchImageActor, Actor::Property::ORIENTATION ), Quaternion( Radian( Degree(360.0f) ), Vector3::ZAXIS ), AlphaFunction::EASE_IN_OUT );
312           mActorAnimation.SetEndAction( Animation::Bake );
313           mActorAnimation.Play();
314         }
315         break;
316
317         // scale
318         case 3:
319         {
320           float animDuration = 1.0f;
321           mActorAnimation = Animation::New(animDuration);
322           mActorAnimation.AnimateBy( Property( mMotionStretchImageActor, Actor::Property::SCALE ), Vector3(2.0f, 2.0f, 2.0f), AlphaFunction::BOUNCE, TimePeriod( 0.0f, 1.0f ) );
323           mActorAnimation.SetEndAction( Animation::Bake );
324           mActorAnimation.Play();
325         }
326         break;
327
328         default:
329           break;
330       }
331
332       mCurrentActorAnimation++;
333       if(NUM_ACTOR_ANIMATIONS == mCurrentActorAnimation)
334       {
335         mCurrentActorAnimation = 0;
336       }
337     }
338   }
339
340   void ToggleActorEffects()
341   {
342     if(!mActorEffectsEnabled)
343     {
344       mActorEffectsEnabled = true;
345       mActorEffectsButton.SetBackgroundImage( mIconEffectsOn );
346     }
347     else
348     {
349       mActorEffectsEnabled = false;
350       mActorEffectsButton.SetBackgroundImage( mIconEffectsOff );
351     }
352   }
353
354   //////////////////////////////////////////////////////////////
355   //
356   // Input handlers
357   //
358   //
359
360   bool OnLayoutButtonClicked( Toolkit::Button button )
361   {
362     ChangeImage();
363     return true;
364   }
365
366   bool OnEffectButtonClicked( Toolkit::Button button )
367   {
368     ToggleActorEffects();
369     return true;
370   }
371
372   /**
373    * Main key event handler
374    */
375   void OnKeyEvent(const KeyEvent& event)
376   {
377     if(event.state == KeyEvent::Down)
378     {
379       if( IsKey( event, Dali::DALI_KEY_ESCAPE) || IsKey( event, Dali::DALI_KEY_BACK) )
380       {
381         mApplication.Quit();
382       }
383     }
384   }
385
386   //////////////////////////////////////////////////////////////
387   //
388   // Misc
389   //
390   //
391
392
393   void ChangeImage()
394   {
395     mCurrentImage++;
396     if(MOTION_STRETCH_NUM_ACTOR_IMAGES == mCurrentImage)
397     {
398       mCurrentImage = 0;
399     }
400
401     Image stretchImage = ResourceImage::New( MOTION_STRETCH_ACTOR_IMAGES[mCurrentImage] );
402     mMotionStretchImageActor.SetImage(stretchImage);
403   }
404
405
406 private:
407   Application&               mApplication;            ///< Application instance
408   Toolkit::Control           mView;
409   Toolkit::ToolBar           mToolBar;
410   Image                      mIconEffectsOff;
411   Image                      mIconEffectsOn;
412   Layer                      mContentLayer;           ///< Content layer (contains actor for this stretch demo)
413
414   PushButton                 mActorEffectsButton;     ///< The actor effects toggling Button.
415
416   // Motion stretch
417   ShaderEffect mMotionStretchEffect;
418   ImageActor mMotionStretchImageActor;
419
420   // animate actor to position where user taps screen
421   Animation mActorTapMovementAnimation;
422
423   // show different animations to demonstrate stretch effect working on an object only movement basis
424   bool mActorEffectsEnabled;
425   Animation mActorAnimation;
426   int mCurrentActorAnimation;
427
428   // offer a selection of images that user can cycle between
429   int mCurrentImage;
430
431   TapGestureDetector mTapGestureDetector;
432
433   DeviceOrientation mOrientation;               ///< Current Device orientation
434   Animation mRotateAnimation;                   ///< Animation for rotating between landscape and portrait.
435
436 };
437
438 void RunTest(Application& app)
439 {
440   MotionStretchExampleApp test(app);
441
442   app.MainLoop();
443 }
444
445 // Entry point for Linux & Tizen applications
446 //
447 int main(int argc, char **argv)
448 {
449   Application app = Application::New(&argc, &argv);
450
451   RunTest(app);
452
453   return 0;
454 }