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