[dali_1.2.7] Merge branch 'devel/master'
[platform/core/uifw/dali-demo.git] / examples / shadows-and-lights / shadows-and-lights-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 // INTERNAL INCLUDES
19 #include "shared/view.h"
20
21 #include <dali/dali.h>
22 #include <dali-toolkit/dali-toolkit.h>
23 #include <dali-toolkit/devel-api/controls/shadow-view/shadow-view.h>
24
25 #include <iostream>
26
27 using namespace Dali;
28 using namespace Dali::Toolkit;
29 using std::string;
30 using namespace DemoHelper;
31
32 namespace
33 {
34 const char* BACKGROUND_IMAGE( DEMO_IMAGE_DIR "background-default.png" );
35 const char* TOOLBAR_IMAGE( DEMO_IMAGE_DIR "top-bar.png" );
36
37 const char* APPLICATION_TITLE_PAN_LIGHT( "Lighting: Pan Light" );
38 const char* APPLICATION_TITLE_ROTATE_OBJECT( "Lighting: Rotate Object" );
39 const char* APPLICATION_TITLE_PAN_SCENE( "Lighting: Pan Scene" );
40 const char* APPLICATION_TITLE_ROTATE_SCENE( "Lighting: Rotate Scene" );
41 const char* CHANGE_EFFECT_IMAGE( DEMO_IMAGE_DIR "icon-change.png" );
42 const char* CHANGE_EFFECT_IMAGE_SELECTED( DEMO_IMAGE_DIR "icon-change-selected.png" );
43 const char* RESET_ICON( DEMO_IMAGE_DIR "icon-reset.png" );
44 const char* RESET_ICON_SELECTED( DEMO_IMAGE_DIR "icon-reset-selected.png" );
45
46 const char* SCENE_IMAGE_1( DEMO_IMAGE_DIR "gallery-small-10.jpg");
47 const char* SCENE_IMAGE_2( DEMO_IMAGE_DIR "gallery-small-42.jpg");
48 const char* SCENE_IMAGE_3( DEMO_IMAGE_DIR "gallery-small-48.jpg");
49
50 const float MIN_PINCH_SCALE( 0.3f );
51 const float MAX_PINCH_SCALE( 2.05f );
52
53 const float R3_2(0.8660254);
54 const Vector3 TOP_POINT(  0.0f, -1.0f,  0.0f);
55 const Vector3 LEFT_POINT( -R3_2, 0.5f,  0.0f);
56 const Vector3 RIGHT_POINT( R3_2, 0.5f,  0.0f);
57 const Vector3 FRONT_POINT( 0.0f, 0.0f, 20.0f);
58
59 const Vector2 DEFAULT_STAGE_SIZE( 480.0f, 800.0f );
60
61 const float X_ROTATION_DISPLACEMENT_FACTOR = 60.f;
62 const float Y_ROTATION_DISPLACEMENT_FACTOR = 60.f;
63 const float LIGHT_PAN_X_DISPLACEMENT_FACTOR = 1/360.f;
64 const float LIGHT_PAN_Y_DISPLACEMENT_FACTOR = 1/360.f;
65
66 }
67
68 /**
69  * This example shows a fixed point light onto an animating set of images
70  * casting a shadow onto a wall. The whole scene can be rotated.
71  */
72
73 class TestApp : public ConnectionTracker
74 {
75 public:
76
77   /**
78    * Constructor
79    * @param application class, stored as reference
80    */
81   TestApp(Application &app)
82   : mApp(app),
83     mPaused(false),
84     mTranslation(22.0f, -1.0f, 0.0f),
85     mSceneXRotation( Degree(-6.0f) ), // Initial values give a reasonable off-straight view.
86     mSceneYRotation( Degree(20.0f) ),
87     mLightXRotation( Degree(-1.5f) ),
88     mLightYRotation( Degree(-9.5f) ),
89     mObjectXRotation(0.0f),
90     mObjectYRotation(0.0f),
91     mPinchScale(0.6f),
92     mScaleAtPinchStart(0.6f),
93     mPanState(PAN_LIGHT)
94   {
95     app.InitSignal().Connect(this, &TestApp::Create);
96     app.TerminateSignal().Connect(this, &TestApp::Terminate);
97   }
98
99   ~TestApp()
100   {
101     // Nothing to do here; All the members of this class get deleted automatically and they delete their children
102   }
103
104 public:
105
106   struct RotationConstraint
107   {
108     RotationConstraint(float sign)
109     : mSign(sign)
110     {
111     }
112
113     void operator()( Quaternion& current, const PropertyInputContainer& inputs )
114     {
115       Radian angle( inputs[0]->GetFloat() );
116       current = Quaternion( angle * mSign, Vector3::YAXIS );
117     }
118
119     float mSign;
120   };
121
122   /**
123    * This method gets called once the main loop of application is up and running
124    */
125   void Create(Application& app)
126   {
127     srand(0); // Want repeatable path
128
129     Stage::GetCurrent().KeyEventSignal().Connect(this, &TestApp::OnKeyEvent);
130
131     CreateToolbarAndView(app);
132     CreateShadowViewAndLights();
133     CreateScene();
134   }
135
136   void CreateToolbarAndView(Application& app)
137   {
138     // Creates a default view with a default tool bar.
139     // The view is added to the stage.
140     Toolkit::ToolBar toolBar;
141     mContents = DemoHelper::CreateView( app,
142                                         mView,
143                                         toolBar,
144                                         BACKGROUND_IMAGE,
145                                         TOOLBAR_IMAGE,
146                                         "" );
147
148     // Add an effect-changing button on the right of the tool bar.
149     Toolkit::PushButton effectChangeButton = Toolkit::PushButton::New();
150     effectChangeButton.SetUnselectedImage( CHANGE_EFFECT_IMAGE );
151     effectChangeButton.SetSelectedImage( CHANGE_EFFECT_IMAGE_SELECTED );
152     effectChangeButton.ClickedSignal().Connect( this, &TestApp::OnEffectButtonClicked );
153     toolBar.AddControl( effectChangeButton, DemoHelper::DEFAULT_VIEW_STYLE.mToolBarButtonPercentage, Toolkit::Alignment::HorizontalRight, DemoHelper::DEFAULT_MODE_SWITCH_PADDING );
154
155     // Add title to the tool bar.
156     mTitleActor = DemoHelper::CreateToolBarLabel( "" );
157     toolBar.AddControl( mTitleActor, DemoHelper::DEFAULT_VIEW_STYLE.mToolBarTitlePercentage, Toolkit::Alignment::HorizontalCenter );
158
159     // Set Title text
160     mTitleActor.SetProperty( TextLabel::Property::TEXT, std::string(APPLICATION_TITLE_PAN_LIGHT) );
161
162     //Add a reset button
163     Toolkit::PushButton resetButton = Toolkit::PushButton::New();
164     resetButton.SetUnselectedImage( RESET_ICON );
165     resetButton.SetSelectedImage( RESET_ICON_SELECTED );
166     resetButton.ClickedSignal().Connect( this, &TestApp::OnResetPressed );
167     toolBar.AddControl( resetButton, DemoHelper::DEFAULT_VIEW_STYLE.mToolBarButtonPercentage, Toolkit::Alignment::HorizontalCenter, DemoHelper::DEFAULT_PLAY_PADDING );
168
169     // Setup
170     mView.SetPosition(Vector3(0.0f, 0.0f, 0.0f));
171
172     mContents.SetBehavior(Layer::LAYER_3D);
173     mContents.SetPosition(mTranslation);
174     mContents.SetOrientation( CalculateWorldRotation( mSceneXRotation, mSceneYRotation ) );
175     mContents.SetScale(mPinchScale, mPinchScale, mPinchScale);
176
177     mPanGestureDetector = PanGestureDetector::New();
178     mPanGestureDetector.Attach( mView );
179     mPanGestureDetector.DetectedSignal().Connect(this, &TestApp::OnPan);
180
181     mPinchGestureDetector = PinchGestureDetector::New();
182     mPinchGestureDetector.Attach( mView );
183     mPinchGestureDetector.DetectedSignal().Connect(this, &TestApp::OnPinch);
184
185     mTapGestureDetector = TapGestureDetector::New();
186     mTapGestureDetector.Attach( mView );
187     mTapGestureDetector.DetectedSignal().Connect(this, &TestApp::OnTap);
188   }
189
190
191
192   void CreateShadowViewAndLights()
193   {
194     mShadowView = Toolkit::ShadowView::New();
195     mShadowView.SetName("Container");
196     mShadowView.SetParentOrigin(ParentOrigin::CENTER);
197     mShadowView.SetAnchorPoint(AnchorPoint::CENTER);
198     mShadowView.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS );
199     mShadowView.SetPointLightFieldOfView( Math::PI / 2.0f);
200     mContents.Add(mShadowView);
201
202     mShadowPlaneBg = ImageView::New( DEMO_IMAGE_DIR "brick-wall.jpg" );
203     mShadowPlaneBg.SetParentOrigin(ParentOrigin::CENTER);
204     mShadowPlaneBg.SetAnchorPoint(AnchorPoint::CENTER);
205     mShadowPlaneBg.SetName("Plane");
206     mShadowPlaneBg.SetSize(1000.0f, 1000.0f);
207     mContents.Add(mShadowPlaneBg);
208     mShadowPlaneBg.SetPosition(Vector3(50.0f, 50.0f, -200.0f));
209
210     mShadowView.SetShadowPlaneBackground(mShadowPlaneBg);
211     mShadowView.Activate();
212
213     mLightAnchor = Actor::New();
214     mLightAnchor.SetParentOrigin(ParentOrigin::CENTER);
215     mLightAnchor.SetAnchorPoint(AnchorPoint::CENTER);
216     mLightAnchor.SetOrientation( CalculateWorldRotation( mLightXRotation, mLightYRotation ) );
217
218     // Work out a scaling factor as the initial light position was calculated for desktop
219     // Need to scale light position as scene actor size is based on stage size (i.e. much bigger on device)
220     Vector2 stageSize( Stage::GetCurrent().GetSize() );
221     float scaleFactor = stageSize.x / DEFAULT_STAGE_SIZE.x;
222
223     mCastingLight = Actor::New();
224     mCastingLight.SetParentOrigin(ParentOrigin::CENTER);
225     mCastingLight.SetAnchorPoint(AnchorPoint::CENTER);
226     mCastingLight.SetPosition( Vector3( 0.0f, 0.0f, 800.0f ) * scaleFactor );
227
228     TextLabel text = TextLabel::New( "Light" );
229     text.SetProperty( TextLabel::Property::POINT_SIZE, 20.0f );
230     text.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::ALL_DIMENSIONS );
231     text.SetColor( Color::BLUE );
232
233     mCastingLight.Add(text);
234     mLightAnchor.Add(mCastingLight);
235     mShadowPlaneBg.Add(mLightAnchor);
236
237     text.SetParentOrigin(ParentOrigin::CENTER);
238     mShadowView.SetPointLight(mCastingLight);
239   }
240
241   void CreateScene()
242   {
243     mSceneActor = Actor::New();
244     mSceneActor.SetParentOrigin(ParentOrigin::CENTER);
245
246     // Create and add images to the scene actor:
247     mImageActor1 = ImageView::New( SCENE_IMAGE_1 );
248     mImageActor2 = ImageView::New( SCENE_IMAGE_2 );
249     mImageActor3 = ImageView::New( SCENE_IMAGE_3 );
250
251     mImageActor1.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::ALL_DIMENSIONS );
252     mImageActor2.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::ALL_DIMENSIONS );
253     mImageActor3.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::ALL_DIMENSIONS );
254
255     mImageActor2.SetParentOrigin(ParentOrigin::CENTER);
256
257     mImageActor1.SetParentOrigin(ParentOrigin::CENTER_LEFT);
258     mImageActor1.SetAnchorPoint(AnchorPoint::CENTER_RIGHT);
259
260     mImageActor3.SetParentOrigin(ParentOrigin::CENTER_RIGHT);
261     mImageActor3.SetAnchorPoint(AnchorPoint::CENTER_LEFT);
262
263     mSceneActor.Add(mImageActor2);
264     mImageActor2.Add(mImageActor1);
265     mImageActor2.Add(mImageActor3);
266
267     Property::Index angleIndex = mImageActor2.RegisterProperty("angle", Property::Value( Dali::ANGLE_30 ) );
268     Source angleSrc( mImageActor2, angleIndex );
269
270     Constraint constraint = Constraint::New<Quaternion>( mImageActor1, Actor::Property::ORIENTATION, RotationConstraint(-1.0f) );
271     constraint.AddSource( angleSrc );
272     constraint.Apply();
273
274     constraint = Constraint::New<Quaternion>( mImageActor3, Actor::Property::ORIENTATION, RotationConstraint(+1.0f) );
275     constraint.AddSource( angleSrc );
276     constraint.Apply();
277
278     mSceneAnimation = Animation::New(2.5f);
279
280     // Want to animate angle from 30 => -30 and back again smoothly.
281
282     mSceneAnimation.AnimateTo( Property( mImageActor2, angleIndex ), Property::Value(-Dali::ANGLE_30), AlphaFunction::SIN );
283
284     mSceneAnimation.SetLooping(true);
285     mSceneAnimation.Play();
286
287     mSceneActor.SetSize(250.0f, 250.0f);
288     mSceneActor.SetPosition(0.0f, 0.0f, 130.0f);
289     mShadowView.Add(mSceneActor);
290   }
291
292
293   Quaternion CalculateWorldRotation( Radian XRotation, Radian YRotation )
294   {
295     Quaternion p( XRotation, Vector3::XAXIS );
296     Quaternion q( YRotation, Vector3::YAXIS );
297     return p*q;
298   }
299
300   void OnTap(Dali::Actor actor, const TapGesture& gesture)
301   {
302     if( mSceneAnimation )
303     {
304       if( ! mPaused )
305       {
306         mSceneAnimation.Pause();
307         mPaused = true;
308       }
309       else
310       {
311         mSceneAnimation.Play();
312         mPaused = false;
313       }
314     }
315   }
316
317   void OnPan(Actor actor, const PanGesture& gesture)
318   {
319     switch (gesture.state)
320     {
321       case Gesture::Continuing:
322       {
323         switch(mPanState)
324         {
325           case PAN_LIGHT:
326           {
327             mLightXRotation = mLightXRotation - gesture.displacement.y * LIGHT_PAN_X_DISPLACEMENT_FACTOR; // X displacement rotates around Y axis
328             mLightXRotation = Clamp(mLightXRotation, -Dali::ANGLE_45, Dali::ANGLE_45 );
329             mLightYRotation = mLightYRotation + gesture.displacement.x * LIGHT_PAN_Y_DISPLACEMENT_FACTOR; // Y displacement rotates around X axis
330             mLightYRotation = Clamp(mLightYRotation, -Dali::ANGLE_45, Dali::ANGLE_45 );
331             mLightAnchor.SetOrientation( CalculateWorldRotation( mLightXRotation, mLightYRotation ) );
332             break;
333           }
334
335           case PAN_SCENE:
336           {
337             mTranslation += Vector3(gesture.displacement.x, gesture.displacement.y, 0.f);
338             mContents.SetPosition(mTranslation);
339             break;
340           }
341
342           case ROTATE_SCENE:
343           {
344             mSceneXRotation = mSceneXRotation - gesture.displacement.y / X_ROTATION_DISPLACEMENT_FACTOR; // X displacement rotates around Y axis
345             mSceneXRotation = Clamp( mSceneXRotation, -Dali::ANGLE_90, Dali::ANGLE_90 );
346             mSceneYRotation = mSceneYRotation + gesture.displacement.x / Y_ROTATION_DISPLACEMENT_FACTOR; // Y displacement rotates around X axis
347             mSceneYRotation = Clamp( mSceneYRotation, -Dali::ANGLE_90, Dali::ANGLE_90 );
348             mContents.SetOrientation( CalculateWorldRotation( mSceneXRotation, mSceneYRotation ) );
349             break;
350           }
351
352           case ROTATE_OBJECT:
353           {
354             mObjectXRotation = mObjectXRotation - gesture.displacement.y / X_ROTATION_DISPLACEMENT_FACTOR; // X displacement rotates around Y axis
355             mObjectYRotation = mObjectYRotation + gesture.displacement.x / Y_ROTATION_DISPLACEMENT_FACTOR; // Y displacement rotates around X axis
356             mSceneActor.SetOrientation( CalculateWorldRotation( mObjectXRotation, mObjectYRotation ) );
357             break;
358           }
359         }
360       }
361       break;
362
363       case Gesture::Finished:
364         // Start animation at last known speed
365         break;
366
367       default:
368         break;
369     }
370   }
371
372   void OnPinch(Actor actor, const PinchGesture& gesture)
373   {
374     if (gesture.state == Gesture::Started)
375     {
376       mScaleAtPinchStart = mContents.GetCurrentScale().x;
377     }
378     mPinchScale = Clamp(mScaleAtPinchStart * gesture.scale, MIN_PINCH_SCALE, MAX_PINCH_SCALE);
379
380     mContents.SetScale(mPinchScale, mPinchScale, mPinchScale);
381   }
382
383   void Terminate(Application& app)
384   {
385     if( mSceneActor )
386     {
387       Stage::GetCurrent().Remove(mSceneActor);
388     }
389     if( mView )
390     {
391       Stage::GetCurrent().Remove(mView);
392     }
393   }
394
395   void OnKeyEvent(const KeyEvent& event)
396   {
397     if(event.state == KeyEvent::Down)
398     {
399       if( IsKey( event, Dali::DALI_KEY_ESCAPE) || IsKey( event, Dali::DALI_KEY_BACK) )
400       {
401         mApp.Quit();
402       }
403     }
404   }
405
406   bool OnEffectButtonClicked( Toolkit::Button button )
407   {
408     switch(mPanState)
409     {
410       case PAN_LIGHT:
411         mPanState = ROTATE_OBJECT;
412         mTitleActor.SetProperty( TextLabel::Property::TEXT, std::string(APPLICATION_TITLE_ROTATE_OBJECT) );
413         break;
414       case ROTATE_OBJECT:
415         mPanState = ROTATE_SCENE;
416         mTitleActor.SetProperty( TextLabel::Property::TEXT, std::string(APPLICATION_TITLE_ROTATE_SCENE) );
417         break;
418       case ROTATE_SCENE:
419         mPanState = PAN_SCENE;
420         mTitleActor.SetProperty( TextLabel::Property::TEXT, std::string(APPLICATION_TITLE_PAN_SCENE) );
421         break;
422       case PAN_SCENE:
423         mPanState = PAN_LIGHT;
424         mTitleActor.SetProperty( TextLabel::Property::TEXT, std::string(APPLICATION_TITLE_PAN_LIGHT) );
425         break;
426       default:
427         break;
428     }
429
430     return true;
431   }
432
433   bool OnResetPressed( Toolkit::Button button )
434   {
435     // Reset translation
436     mTranslation = Vector3::ZERO;
437     mContents.SetPosition(mTranslation);
438
439     // Align scene so that light anchor orientation is Z Axis
440     mSceneXRotation = -mLightXRotation;
441     mSceneYRotation = -mLightYRotation;
442     mContents.SetOrientation( CalculateWorldRotation( mSceneXRotation, mSceneYRotation ) );
443
444     return true;
445   }
446
447 private:
448   Application&              mApp;
449   Toolkit::Control          mView;
450   Layer                     mContents;
451   Actor                     mSceneActor;
452   Animation                 mAnimation;
453   Animation                 mSceneAnimation;
454   bool                      mPaused;
455   Toolkit::ShadowView       mShadowView;
456   ImageView                 mShadowPlaneBg;
457   ImageView                 mShadowPlane;
458   Actor                     mCastingLight;
459   Actor                     mLightAnchor;
460   ImageView                 mImageActor1;
461   ImageView                 mImageActor2;
462   ImageView                 mImageActor3;
463   PanGestureDetector        mPanGestureDetector;
464   PinchGestureDetector      mPinchGestureDetector;
465   TapGestureDetector        mTapGestureDetector;
466   Vector3                   mTranslation;
467   Radian                    mSceneXRotation;
468   Radian                    mSceneYRotation;
469   Radian                    mLightXRotation;
470   Radian                    mLightYRotation;
471   Radian                    mObjectXRotation;
472   Radian                    mObjectYRotation;
473   float                     mPinchScale;
474   float                     mScaleAtPinchStart;
475
476   Property::Index           mAngle1Index;
477   Property::Index           mAngle3Index;
478
479   Toolkit::TextLabel         mTitleActor;
480
481   enum PanState
482   {
483     PAN_SCENE,
484     ROTATE_SCENE,
485     PAN_LIGHT,
486     ROTATE_OBJECT
487   };
488
489   PanState                  mPanState;
490 };
491
492 /*****************************************************************************/
493
494 static void
495 RunTest(Application& app)
496 {
497   TestApp theApp(app);
498   app.MainLoop();
499 }
500
501 /*****************************************************************************/
502
503 int DALI_EXPORT_API main(int argc, char **argv)
504 {
505   Application app = Application::New(&argc, &argv, DEMO_THEME_PATH);
506
507   RunTest(app);
508
509   return 0;
510 }