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