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