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