7a0548a9f280cbdb51d211d9de5a910400eb6a25
[platform/core/uifw/dali-demo.git] / examples / mesh-visual / mesh-visual-example.cpp
1 #include <dali-toolkit/dali-toolkit.h>
2
3 using namespace Dali;
4 using namespace Dali::Toolkit;
5
6 namespace
7 {
8 // Keeps information about each model for access.
9 struct Model
10 {
11   Control   control;           // Control housing the mesh visual of the model.
12   Animation rotationAnimation; // Automatically rotates when left alone.
13 };
14
15 // Files for meshes
16 const char* const MODEL_FILE_TABLE[] =
17   {
18     DEMO_MODEL_DIR "Dino.obj",
19     DEMO_MODEL_DIR "ToyRobot-Metal.obj",
20     DEMO_MODEL_DIR "Toyrobot-Plastic.obj"};
21
22 const char* const MATERIAL_FILE_TABLE[] =
23   {
24     DEMO_MODEL_DIR "Dino.mtl",
25     DEMO_MODEL_DIR "ToyRobot-Metal.mtl",
26     DEMO_MODEL_DIR "Toyrobot-Plastic.mtl"};
27
28 const char* const TEXTURES_PATH(DEMO_IMAGE_DIR "");
29
30 // Possible shading modes.
31 MeshVisual::ShadingMode::Value SHADING_MODE_TABLE[] =
32   {
33     MeshVisual::ShadingMode::TEXTURED_WITH_DETAILED_SPECULAR_LIGHTING,
34     MeshVisual::ShadingMode::TEXTURED_WITH_SPECULAR_LIGHTING,
35     MeshVisual::ShadingMode::TEXTURELESS_WITH_DIFFUSE_LIGHTING};
36
37 // Button labels.
38 const char* const PAUSE  = "  ||  ";
39 const char* const PLAY   = "  >  ";
40 const char* const FIXED  = "FIXED";
41 const char* const MANUAL = "MANUAL";
42 const char* const FRONT  = "FRONT";
43 const char* const BACK   = "BACK";
44
45 // Image urls for the light.
46 const char* const LIGHT_URL_FRONT = DEMO_IMAGE_DIR "light-icon-front.png";
47 const char* const LIGHT_URL_BACK  = DEMO_IMAGE_DIR "light-icon-back.png";
48
49 const float X_ROTATION_DISPLACEMENT_FACTOR = 60.0f;
50 const float Y_ROTATION_DISPLACEMENT_FACTOR = 60.0f;
51 const float MODEL_SCALE                    = 0.75f;
52 const float LIGHT_SCALE                    = 0.15f;
53 const float BUTTONS_OFFSET_BOTTOM          = 0.08f;
54 const float BUTTONS_OFFSET_SIDE            = 0.2f;
55 const int   NUM_MESHES                     = 2;
56
57 // Used to identify actors.
58 const int MODEL_TAG = 0;
59 const int LIGHT_TAG = 1;
60 const int LAYER_TAG = 2;
61
62 const Vector4 WINDOW_COLOR(211.0f / 255.0f, 211.0f / 255.0f, 211.0f / 255.0f, 1.0f); ///< The color of the window
63
64 } // unnamed namespace
65
66 class MeshVisualController : public ConnectionTracker
67 {
68 public:
69   MeshVisualController(Application& application)
70   : mApplication(application), //Store handle to the application.
71     mModelIndex(1),            //Start with metal robot.
72     mShadingModeIndex(0),      //Start with texture and detailed specular lighting.
73     mTag(-1),                  //Non-valid default, which will get set to a correct value when used.
74     mSelectedModelIndex(-1),   //Non-valid default, which will get set to a correct value when used.
75     mPaused(false),            //Animations play by default.
76     mLightFixed(true),         //The light is fixed by default.
77     mLightFront(true)          //The light is in front by default.
78   {
79     // Connect to the Application's Init signal
80     mApplication.InitSignal().Connect(this, &MeshVisualController::Create);
81   }
82
83   ~MeshVisualController()
84   {
85   }
86
87   // The Init signal is received once (only) during the Application lifetime
88   void Create(Application& application)
89   {
90     // Get a handle to the window
91     Window window = application.GetWindow();
92     window.SetBackgroundColor(WINDOW_COLOR);
93
94     //Set up root layer to receive touch gestures.
95     Layer rootLayer = window.GetRootLayer();
96     rootLayer.RegisterProperty("Tag", LAYER_TAG); //Used to differentiate between different kinds of actor.
97     rootLayer.TouchedSignal().Connect(this, &MeshVisualController::OnTouch);
98
99     //Place models on the scene.
100     SetupModels(rootLayer);
101
102     //Place buttons on the scene.
103     SetupButtons(rootLayer);
104
105     //Add a light to the scene.
106     SetupLight(rootLayer);
107
108     //Allow for exiting of the application via key presses.
109     window.KeyEventSignal().Connect(this, &MeshVisualController::OnKeyEvent);
110   }
111
112   //Loads and adds the models to the scene, inside containers for hit detection.
113   void SetupModels(Layer layer)
114   {
115     //Add containers to house each renderer-holding-actor.
116     for(int i = 0; i < NUM_MESHES; i++)
117     {
118       mContainers[i] = Actor::New();
119       mContainers[i].SetResizePolicy(ResizePolicy::SIZE_RELATIVE_TO_PARENT, Dimension::ALL_DIMENSIONS);
120       mContainers[i].RegisterProperty("Tag", MODEL_TAG);            //Used to differentiate between different kinds of actor.
121       mContainers[i].RegisterProperty("Model", Property::Value(i)); //Used to index into the model.
122       mContainers[i].TouchedSignal().Connect(this, &MeshVisualController::OnTouch);
123       layer.Add(mContainers[i]);
124     }
125
126     //Position each container individually on screen
127
128     //Main, central model
129     mContainers[0].SetProperty(Actor::Property::SIZE_MODE_FACTOR, Vector3(MODEL_SCALE, MODEL_SCALE, 0.0f));
130     mContainers[0].SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
131     mContainers[0].SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
132
133     //Top left model
134     mContainers[1].SetProperty(Actor::Property::SIZE_MODE_FACTOR, Vector3(MODEL_SCALE / 3.0f, MODEL_SCALE / 3.0f, 0.0f));
135     mContainers[1].SetProperty(Actor::Property::PARENT_ORIGIN, Vector3(0.05, 0.03, 0.5)); //Offset from top left
136     mContainers[1].SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
137
138     //Set up models
139     for(int i = 0; i < NUM_MESHES; i++)
140     {
141       //Create control to display model
142       Control control = Control::New();
143       control.SetResizePolicy(ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS);
144       control.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
145       control.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
146       mContainers[i].Add(control);
147
148       //Make model spin to demonstrate 3D
149       Animation rotationAnimation = Animation::New(15.0f);
150       float     spin              = i % 2 == 0 ? 1.0f : -1.0f; //Make actors spin in different directions to better show independence.
151       rotationAnimation.AnimateBy(Property(control, Actor::Property::ORIENTATION),
152                                   Quaternion(Degree(0.0f), Degree(spin * 360.0f), Degree(0.0f)));
153       rotationAnimation.SetLooping(true);
154       rotationAnimation.Play();
155
156       //Store model information in corresponding structs.
157       mModels[i].control           = control;
158       mModels[i].rotationAnimation = rotationAnimation;
159     }
160
161     //Calling this sets the model in the controls.
162     ReloadModel();
163   }
164
165   //Place the various buttons on the bottom of the screen, with title labels where necessary.
166   void SetupButtons(Layer layer)
167   {
168     //Actor for positioning model and shading mode buttons.
169     Actor positionActorModel = Actor::New();
170     positionActorModel.SetProperty(Actor::Property::PARENT_ORIGIN, Vector3(BUTTONS_OFFSET_SIDE, 1.0 - BUTTONS_OFFSET_BOTTOM, 0.5));
171     positionActorModel.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::BOTTOM_CENTER);
172     layer.Add(positionActorModel);
173
174     //Create button for model changing.
175     PushButton modelButton = Toolkit::PushButton::New();
176     modelButton.SetResizePolicy(ResizePolicy::USE_NATURAL_SIZE, Dimension::ALL_DIMENSIONS);
177     modelButton.ClickedSignal().Connect(this, &MeshVisualController::OnChangeModelClicked);
178     modelButton.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_CENTER);
179     modelButton.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::BOTTOM_CENTER);
180     modelButton.SetProperty(Toolkit::Button::Property::LABEL, "Model");
181     positionActorModel.Add(modelButton);
182
183     //Create button for shading mode changing.
184     PushButton shadingModeButton = Toolkit::PushButton::New();
185     shadingModeButton.SetResizePolicy(ResizePolicy::USE_NATURAL_SIZE, Dimension::ALL_DIMENSIONS);
186     shadingModeButton.ClickedSignal().Connect(this, &MeshVisualController::OnChangeShadingModeClicked);
187     shadingModeButton.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::BOTTOM_CENTER);
188     shadingModeButton.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_CENTER);
189     shadingModeButton.SetProperty(Toolkit::Button::Property::LABEL, "Shading Mode");
190     positionActorModel.Add(shadingModeButton);
191
192     //Text label title for changing model or shading mode.
193     TextLabel changeTitleLabel = TextLabel::New("Change");
194     changeTitleLabel.SetResizePolicy(ResizePolicy::USE_NATURAL_SIZE, Dimension::ALL_DIMENSIONS);
195     changeTitleLabel.SetProperty(TextLabel::Property::UNDERLINE, "{\"thickness\":\"2.0\"}");
196     changeTitleLabel.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_CENTER);
197     changeTitleLabel.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::BOTTOM_CENTER);
198     modelButton.Add(changeTitleLabel);
199
200     //Create button for pausing animations.
201     PushButton pauseButton = Toolkit::PushButton::New();
202     pauseButton.SetResizePolicy(ResizePolicy::USE_NATURAL_SIZE, Dimension::ALL_DIMENSIONS);
203     pauseButton.ClickedSignal().Connect(this, &MeshVisualController::OnPauseClicked);
204     pauseButton.SetProperty(Actor::Property::PARENT_ORIGIN, Vector3(0.5, 1.0 - BUTTONS_OFFSET_BOTTOM, 0.5));
205     pauseButton.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
206     pauseButton.SetProperty(Toolkit::Button::Property::LABEL, PAUSE);
207     layer.Add(pauseButton);
208
209     //Actor for positioning light position buttons.
210     Actor positionActorLight = Actor::New();
211     positionActorLight.SetProperty(Actor::Property::PARENT_ORIGIN, Vector3(1.0 - BUTTONS_OFFSET_SIDE, 1.0 - BUTTONS_OFFSET_BOTTOM, 0.5));
212     positionActorLight.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::BOTTOM_CENTER);
213     layer.Add(positionActorLight);
214
215     //Create button for switching between manual and fixed light position.
216     PushButton lightModeButton = Toolkit::PushButton::New();
217     lightModeButton.SetResizePolicy(ResizePolicy::USE_NATURAL_SIZE, Dimension::ALL_DIMENSIONS);
218     lightModeButton.ClickedSignal().Connect(this, &MeshVisualController::OnChangeLightModeClicked);
219     lightModeButton.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_CENTER);
220     lightModeButton.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::BOTTOM_CENTER);
221     lightModeButton.SetProperty(Toolkit::Button::Property::LABEL, FIXED);
222     positionActorLight.Add(lightModeButton);
223
224     //Create button for switching between front and back light position.
225     PushButton lightSideButton = Toolkit::PushButton::New();
226     lightSideButton.SetResizePolicy(ResizePolicy::USE_NATURAL_SIZE, Dimension::ALL_DIMENSIONS);
227     lightSideButton.ClickedSignal().Connect(this, &MeshVisualController::OnChangeLightSideClicked);
228     lightSideButton.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::BOTTOM_CENTER);
229     lightSideButton.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_CENTER);
230     lightSideButton.SetProperty(Toolkit::Button::Property::LABEL, FRONT);
231     positionActorLight.Add(lightSideButton);
232
233     //Text label title for light position mode.
234     TextLabel lightTitleLabel = TextLabel::New("Light Position");
235     lightTitleLabel.SetResizePolicy(ResizePolicy::USE_NATURAL_SIZE, Dimension::ALL_DIMENSIONS);
236     lightTitleLabel.SetProperty(TextLabel::Property::UNDERLINE, "{\"thickness\":\"2.0\"}");
237     lightTitleLabel.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_CENTER);
238     lightTitleLabel.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::BOTTOM_CENTER);
239     lightModeButton.Add(lightTitleLabel);
240   }
241
242   //Add a point light source the the scene, on a layer above the first.
243   void SetupLight(Layer baseLayer)
244   {
245     //Create control to act as light source of scene.
246     mLightSource = Control::New();
247     mLightSource.RegisterProperty("Tag", LIGHT_TAG);
248
249     //Set size of control based on screen dimensions.
250     Window  window     = mApplication.GetWindow();
251     Vector2 windowSize = window.GetSize();
252     if(windowSize.width < windowSize.height)
253     {
254       //Scale to width.
255       mLightSource.SetResizePolicy(ResizePolicy::SIZE_RELATIVE_TO_PARENT, Dimension::WIDTH);
256       mLightSource.SetResizePolicy(ResizePolicy::DIMENSION_DEPENDENCY, Dimension::HEIGHT);
257       mLightSource.SetProperty(Actor::Property::SIZE_MODE_FACTOR, Vector3(LIGHT_SCALE, 0.0f, 0.0f));
258     }
259     else
260     {
261       //Scale to height.
262       mLightSource.SetResizePolicy(ResizePolicy::SIZE_RELATIVE_TO_PARENT, Dimension::HEIGHT);
263       mLightSource.SetResizePolicy(ResizePolicy::DIMENSION_DEPENDENCY, Dimension::WIDTH);
264       mLightSource.SetProperty(Actor::Property::SIZE_MODE_FACTOR, Vector3(0.0f, LIGHT_SCALE, 0.0f));
265     }
266
267     //Set position relative to top left, as the light source property is also relative to the top left.
268     mLightSource.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT);
269     mLightSource.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
270     mLightSource.SetProperty(Actor::Property::POSITION, Vector2(windowSize.width * 0.85f, windowSize.height * 0.125));
271
272     //Supply an image to represent the light.
273     SetLightImage();
274
275     //Connect to touch signal for dragging.
276     mLightSource.TouchedSignal().Connect(this, &MeshVisualController::OnTouch);
277
278     //Place the light source on a layer above the base, so that it is rendered above everything else.
279     Layer upperLayer = Layer::New();
280     upperLayer.SetResizePolicy(ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS);
281     upperLayer.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
282     upperLayer.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
283
284     baseLayer.Add(upperLayer);
285     upperLayer.Add(mLightSource);
286
287     //Decide which light to use to begin with.
288     SetLightMode();
289   }
290
291   //Sets the image to use for the light source depending on whether the light is in front or behind.
292   void SetLightImage()
293   {
294     std::string imageUrl;
295
296     if(mLightFront)
297     {
298       imageUrl = LIGHT_URL_FRONT;
299     }
300     else
301     {
302       imageUrl = LIGHT_URL_BACK;
303     }
304
305     Property::Map lightMap;
306     lightMap.Insert(Toolkit::Visual::Property::TYPE, Visual::IMAGE);
307     lightMap.Insert(ImageVisual::Property::URL, imageUrl);
308     mLightSource.SetProperty(Control::Property::BACKGROUND, Property::Value(lightMap));
309   }
310
311   //Updates the displayed models to account for parameter changes.
312   void ReloadModel()
313   {
314     //Create mesh property map
315     Property::Map map;
316     map.Insert(Toolkit::Visual::Property::TYPE, Visual::MESH);
317     map.Insert(Visual::Property::TRANSFORM,
318                Property::Map().Add(Visual::Transform::Property::ORIGIN, Align::CENTER).Add(Visual::Transform::Property::ANCHOR_POINT, Align::CENTER));
319     map.Insert(MeshVisual::Property::OBJECT_URL, MODEL_FILE_TABLE[mModelIndex]);
320     map.Insert(MeshVisual::Property::MATERIAL_URL, MATERIAL_FILE_TABLE[mModelIndex]);
321     map.Insert(MeshVisual::Property::TEXTURES_PATH, TEXTURES_PATH);
322     map.Insert(MeshVisual::Property::SHADING_MODE, SHADING_MODE_TABLE[mShadingModeIndex]);
323
324     //Set the two controls to use the mesh
325     for(int i = 0; i < NUM_MESHES; i++)
326     {
327       mModels[i].control.SetProperty(Control::Property::BACKGROUND, Property::Value(map));
328     }
329   }
330
331   //Set the mode used to light the models.
332   void SetLightMode()
333   {
334     if(mLightFixed)
335     {
336       UseFixedLight();
337     }
338     else
339     {
340       UseManualLight();
341     }
342   }
343
344   //Make the models use a fixed, invisible light above the center of the window.
345   void UseFixedLight()
346   {
347     //Hide draggable source
348     mLightSource.SetProperty(Actor::Property::VISIBLE, false);
349
350     //Use window dimensions to place light at center, offset in z axis.
351     Window  window        = mApplication.GetWindow();
352     float   width         = window.GetSize().GetWidth();
353     float   height        = window.GetSize().GetHeight();
354     Vector3 lightPosition = Vector3(width / 2.0f, height / 2.0f, (mLightFront ? 1 : -1) * std::max(width, height) * 5.0f);
355
356     //Set global light position
357     for(int i = 0; i < NUM_MESHES; ++i)
358     {
359       mModels[i].control.RegisterProperty("lightPosition", lightPosition, Property::ANIMATABLE);
360     }
361   }
362
363   //Make the models use a light source that the user can drag around.
364   void UseManualLight()
365   {
366     //Show draggable source
367     mLightSource.SetProperty(Actor::Property::VISIBLE, true);
368
369     //Update to switch light position of models to that of the source.
370     UpdateLight();
371   }
372
373   //Updates the light position for each model to account for changes in the source on screen.
374   void UpdateLight()
375   {
376     //Set light position to the x and y of the light control, offset into/out of the screen.
377     Vector3 controlPosition = mLightSource.GetCurrentProperty<Vector3>(Actor::Property::POSITION);
378     Vector3 lightPosition   = Vector3(controlPosition.x, controlPosition.y, (mLightFront ? 1 : -1) * mApplication.GetWindow().GetSize().GetWidth() / 2.0f);
379
380     for(int i = 0; i < NUM_MESHES; ++i)
381     {
382       mModels[i].control.RegisterProperty("lightPosition", lightPosition, Property::ANIMATABLE);
383     }
384   }
385
386   //If the light source is touched, move it by dragging it.
387   //If a model is touched, rotate it by panning around.
388   bool OnTouch(Actor actor, const TouchEvent& touch)
389   {
390     switch(touch.GetState(0))
391     {
392       case PointState::DOWN:
393       {
394         //Determine what was touched.
395         actor.GetProperty(actor.GetPropertyIndex("Tag")).Get(mTag);
396
397         if(mTag == MODEL_TAG)
398         {
399           //Find out which model has been selected
400           actor.GetProperty(actor.GetPropertyIndex("Model")).Get(mSelectedModelIndex);
401
402           //Pause current animation, as the touch gesture will be used to manually rotate the model
403           mModels[mSelectedModelIndex].rotationAnimation.Stop();
404
405           //Store start points.
406           mLastTouchPosition = touch.GetScreenPosition(0);
407         }
408
409         break;
410       }
411       case PointState::MOTION:
412       {
413         //Switch on the kind of actor we're interacting with.
414         switch(mTag)
415         {
416           case MODEL_TAG: //Rotate model
417           {
418             //Calculate displacement and corresponding rotation.
419             const Vector2 touchPosition = touch.GetScreenPosition(0);
420             const Vector2 displacement = touchPosition - mLastTouchPosition;
421             mLastTouchPosition = touchPosition;
422
423             const Quaternion q(Radian(displacement.y / -Y_ROTATION_DISPLACEMENT_FACTOR), Radian(displacement.x / X_ROTATION_DISPLACEMENT_FACTOR), Radian(0.f));
424             const Quaternion q0 = mModels[mSelectedModelIndex].control.GetProperty(Actor::Property::ORIENTATION).Get<Quaternion>();
425
426             //Apply rotation.
427             mModels[mSelectedModelIndex].control.SetProperty(Actor::Property::ORIENTATION, q * q0);
428
429             break;
430           }
431           case LIGHT_TAG: //Drag light
432           {
433             //Set light source to new position and update the models accordingly.
434             mLightSource.SetProperty(Actor::Property::POSITION, Vector3(touch.GetScreenPosition(0)));
435             UpdateLight();
436
437             break;
438           }
439         }
440
441         break;
442       }
443       case PointState::INTERRUPTED: //Same as finished.
444       case PointState::FINISHED:
445       {
446         if(mTag == MODEL_TAG)
447         {
448           //Return to automatic animation
449           if(!mPaused)
450           {
451             mModels[mSelectedModelIndex].rotationAnimation.Play();
452           }
453         }
454
455         break;
456       }
457       default:
458       {
459         //Other touch states do nothing.
460         break;
461       }
462     }
463
464     return true;
465   }
466
467   //Cycle through the list of models.
468   bool OnChangeModelClicked(Toolkit::Button button)
469   {
470     ++mModelIndex %= 3;
471
472     ReloadModel();
473
474     return true;
475   }
476
477   //Cycle through the list of shading modes.
478   bool OnChangeShadingModeClicked(Toolkit::Button button)
479   {
480     ++mShadingModeIndex %= 3;
481
482     ReloadModel();
483
484     return true;
485   }
486
487   //Pause all animations, and keep them paused even after user panning.
488   //This button is a toggle, so pressing again will start the animations again.
489   bool OnPauseClicked(Toolkit::Button button)
490   {
491     //Toggle pause state.
492     mPaused = !mPaused;
493
494     //If we wish to pause animations, do so and keep them paused.
495     if(mPaused)
496     {
497       for(int i = 0; i < NUM_MESHES; ++i)
498       {
499         mModels[i].rotationAnimation.Pause();
500       }
501
502       button.SetProperty(Toolkit::Button::Property::LABEL, PLAY);
503     }
504     else //Unpause all animations again.
505     {
506       for(int i = 0; i < NUM_MESHES; ++i)
507       {
508         mModels[i].rotationAnimation.Play();
509       }
510
511       button.SetProperty(Toolkit::Button::Property::LABEL, PAUSE);
512     }
513
514     return true;
515   }
516
517   //Switch between a fixed light source above/behind the screen, and a light source the user can drag around.
518   bool OnChangeLightModeClicked(Toolkit::Button button)
519   {
520     //Toggle state.
521     mLightFixed = !mLightFixed;
522
523     if(mLightFixed)
524     {
525       button.SetProperty(Toolkit::Button::Property::LABEL, FIXED);
526     }
527     else
528     {
529       button.SetProperty(Toolkit::Button::Property::LABEL, MANUAL);
530     }
531
532     SetLightMode();
533
534     return true;
535   }
536
537   //Switch between the light being in front of and behind the models.
538   bool OnChangeLightSideClicked(Toolkit::Button button)
539   {
540     //Toggle state.
541     mLightFront = !mLightFront;
542
543     if(mLightFront)
544     {
545       button.SetProperty(Toolkit::Button::Property::LABEL, FRONT);
546     }
547     else
548     {
549       button.SetProperty(Toolkit::Button::Property::LABEL, BACK);
550     }
551
552     //Change light image.
553     SetLightImage();
554
555     //Update light to account for the change.
556     SetLightMode();
557
558     return true;
559   }
560
561   //If escape or the back button is pressed, quit the application (and return to the launcher)
562   void OnKeyEvent(const KeyEvent& event)
563   {
564     if(event.GetState() == KeyEvent::DOWN)
565     {
566       if(IsKey(event, DALI_KEY_ESCAPE) || IsKey(event, DALI_KEY_BACK))
567       {
568         mApplication.Quit();
569       }
570     }
571   }
572
573 private:
574   Application& mApplication;
575
576   //The models displayed on screen, including information about rotation.
577   Model mModels[NUM_MESHES];
578   Actor mContainers[NUM_MESHES];
579
580   //Acts as a global light source, which can be dragged around.
581   Control mLightSource;
582
583   //Used to detect panning to rotate the selected model.
584   Vector2 mLastTouchPosition;
585   Vector2 mRotationStart;
586
587   int  mModelIndex;         //Index of model to load.
588   int  mShadingModeIndex;   //Index of shading mode to use.
589   int  mTag;                //Identifies what kind of actor has been selected in OnTouch.
590   int  mSelectedModelIndex; //Index of model selected on screen.
591   bool mPaused;             //If true, all animations are paused and should stay so.
592   bool mLightFixed;         //If false, the light is in manual.
593   bool mLightFront;         //Bool for light being in front or behind the models.
594 };
595
596 int DALI_EXPORT_API main(int argc, char** argv)
597 {
598   Application          application = Application::New(&argc, &argv, DEMO_THEME_PATH);
599   MeshVisualController test(application);
600   application.MainLoop();
601   return 0;
602 }