805a5c197d65a035d79bc62be4d718a34ead5e01
[platform/core/uifw/dali-demo.git] / examples / mesh-renderer / mesh-renderer-example.cpp
1 #include <dali-toolkit/dali-toolkit.h>
2 #include <dali/public-api/object/property-map.h>
3
4 using namespace Dali;
5 using namespace Dali::Toolkit;
6
7 namespace
8 {
9   //Keeps information about each model for access.
10   struct Model
11   {
12     Control control; // Control housing the mesh renderer of the model.
13     Vector2 rotation; // Keeps track of rotation about x and y axis for manual rotation.
14     Animation rotationAnimation; // Automatically rotates when left alone.
15   };
16
17   //Files for meshes
18   const char * const MODEL_FILE[] =
19   {
20       DEMO_MODEL_DIR "Dino.obj",
21       DEMO_MODEL_DIR "ToyRobot-Metal.obj",
22       DEMO_MODEL_DIR "Toyrobot-Plastic.obj"
23   };
24
25   const char * const MATERIAL_FILE[] =
26   {
27       DEMO_MODEL_DIR "Dino.mtl",
28       DEMO_MODEL_DIR "ToyRobot-Metal.mtl",
29       DEMO_MODEL_DIR "Toyrobot-Plastic.mtl"
30   };
31
32   const char * const TEXTURES_PATH( DEMO_IMAGE_DIR "" );
33
34   //Possible shader options.
35   const char * const SHADER_TYPE[] =
36   {
37     "allTextures",
38     "diffuseTexture",
39     "textureless"
40   };
41
42   //Files for background and toolbar
43   const char * const BACKGROUND_IMAGE( DEMO_IMAGE_DIR "background-1.jpg");
44
45   const float X_ROTATION_DISPLACEMENT_FACTOR = 60.0f;
46   const float Y_ROTATION_DISPLACEMENT_FACTOR = 60.0f;
47   const float MODEL_SCALE = 0.75f;
48   const int NUM_MESHES = 3;
49
50 } //End namespace
51
52 class MeshRendererController : public ConnectionTracker
53 {
54 public:
55
56   MeshRendererController( Application& application )
57   : mApplication( application ),   //Store handle to the application.
58     mModelIndex( 1 ),              //Start with metal robot.
59     mShaderIndex( 0 ),             //Start with all textures.
60     mSelectedModelIndex( 0 )       //Non-valid default, which will get set to a correct value when used.
61   {
62     // Connect to the Application's Init signal
63     mApplication.InitSignal().Connect( this, &MeshRendererController::Create );
64   }
65
66   ~MeshRendererController()
67   {
68   }
69
70   // The Init signal is received once (only) during the Application lifetime
71   void Create( Application& application )
72   {
73     // Get a handle to the stage
74     Stage stage = Stage::GetCurrent();
75
76     //Add background
77     ImageView backView = ImageView::New( BACKGROUND_IMAGE );
78     backView.SetAnchorPoint( AnchorPoint::TOP_LEFT );
79     stage.Add( backView );
80
81     //Setup and load the 3D models and buttons
82     LoadScene();
83
84     //Allow for exiting of the application via key presses.
85     stage.KeyEventSignal().Connect( this, &MeshRendererController::OnKeyEvent );
86   }
87
88   //Sets up the on-screen elements.
89   void LoadScene()
90   {
91     Stage stage = Stage::GetCurrent();
92
93     //Set up 3D layer to place objects on.
94     Layer layer = Layer::New();
95     layer.SetParentOrigin( ParentOrigin::CENTER );
96     layer.SetAnchorPoint( AnchorPoint::CENTER );
97     layer.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS );
98     layer.SetBehavior( Layer::LAYER_2D ); //We use a 2D layer as this is closer to UI work than full 3D scene creation.
99     layer.SetDepthTestDisabled( false ); //Enable depth testing, as otherwise the 2D layer would not do so.
100     stage.Add( layer );
101
102     //Create gesture detector for panning of models.
103     mPanGestureDetector = PanGestureDetector::New();
104     mPanGestureDetector.DetectedSignal().Connect( this, &MeshRendererController::OnPan );
105
106     //Add containers to house each renderer-holding-actor.
107     for( int i = 0; i < NUM_MESHES; i++ )
108     {
109       mContainers[i] = Actor::New();
110       mContainers[i].SetResizePolicy( ResizePolicy::SIZE_RELATIVE_TO_PARENT, Dimension::ALL_DIMENSIONS );
111       mContainers[i].RegisterProperty( "Tag", Property::Value( i ) ); //Used to identify the actor and index into the model.
112
113       //Position each container on screen
114       if( i == 0 )
115       {
116         //Main, central model
117         mContainers[i].SetSizeModeFactor( Vector3( MODEL_SCALE, MODEL_SCALE, 0.0f ) );
118         mContainers[i].SetParentOrigin( ParentOrigin::CENTER );
119         mContainers[i].SetAnchorPoint( AnchorPoint::CENTER );
120       }
121       else if( i == 1 )
122       {
123         //Top left model
124         mContainers[i].SetSizeModeFactor( Vector3( MODEL_SCALE / 3.0f, MODEL_SCALE / 3.0f, 0.0f ) );
125         mContainers[i].SetParentOrigin( Vector3( 0.05, 0.03, 0.5 ) ); //Offset from top left
126         mContainers[i].SetAnchorPoint( AnchorPoint::TOP_LEFT );
127       }
128       else if( i == 2 )
129       {
130         //Top right model
131         mContainers[i].SetSizeModeFactor( Vector3( MODEL_SCALE / 3.0f, MODEL_SCALE / 3.0f, 0.0f ) );
132         mContainers[i].SetParentOrigin( Vector3( 0.95, 0.03, 0.5 ) ); //Offset from top right
133         mContainers[i].SetAnchorPoint( AnchorPoint::TOP_RIGHT );
134       }
135
136       mPanGestureDetector.Attach( mContainers[i] );
137       layer.Add( mContainers[i] );
138     }
139
140     //Set up models
141     for( int i = 0; i < NUM_MESHES; i++ )
142     {
143       //Create control to display model
144       Control control = Control::New();
145       control.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS );
146       control.SetParentOrigin( ParentOrigin::CENTER );
147       control.SetAnchorPoint( AnchorPoint::CENTER );
148       mContainers[i].Add( control );
149
150       //Make model spin to demonstrate 3D
151       Animation rotationAnimation = Animation::New( 15.0f );
152       float spin = i % 2 == 0 ? 1.0f : -1.0f; //Make actors spin in different directions to better show independence.
153       rotationAnimation.AnimateBy( Property( control, Actor::Property::ORIENTATION ),
154                                    Quaternion( Degree( 0.0f ), Degree( spin * 360.0f ), Degree( 0.0f ) ) );
155       rotationAnimation.SetLooping( true );
156       rotationAnimation.Play();
157
158       //Store model information in corresponding structs.
159       mModels[i].control = control;
160       mModels[i].rotation.x = 0.0f;
161       mModels[i].rotation.y = 0.0f;
162       mModels[i].rotationAnimation = rotationAnimation;
163     }
164
165     //Calling this sets the model in the controls.
166     ReloadModel();
167
168     //Create button for model changing
169     Toolkit::PushButton modelButton = Toolkit::PushButton::New();
170     modelButton.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::ALL_DIMENSIONS );
171     modelButton.ClickedSignal().Connect( this, &MeshRendererController::OnChangeModelClicked );
172     modelButton.SetParentOrigin( Vector3( 0.1, 0.95, 0.5 ) ); //Offset from bottom left
173     modelButton.SetAnchorPoint( AnchorPoint::BOTTOM_LEFT );
174     modelButton.SetLabelText( "Change Model" );
175     layer.Add( modelButton );
176
177     //Create button for shader changing
178     Toolkit::PushButton shaderButton = Toolkit::PushButton::New();
179     shaderButton.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::ALL_DIMENSIONS );
180     shaderButton.ClickedSignal().Connect( this, &MeshRendererController::OnChangeShaderClicked );
181     shaderButton.SetParentOrigin( Vector3( 0.9, 0.95, 0.5 ) ); //Offset from bottom right
182     shaderButton.SetAnchorPoint( AnchorPoint::BOTTOM_RIGHT );
183     shaderButton.SetLabelText( "Change Shader" );
184     layer.Add( shaderButton );
185   }
186
187   //Updates the displayed models to account for parameter changes.
188   void ReloadModel()
189   {
190     //Create mesh property map
191     Property::Map map;
192     map.Insert( "rendererType", "mesh" );
193     map.Insert( "objectUrl", MODEL_FILE[mModelIndex] );
194     map.Insert( "materialUrl", MATERIAL_FILE[mModelIndex] );
195     map.Insert( "texturesPath", TEXTURES_PATH );
196     map.Insert( "shaderType", SHADER_TYPE[mShaderIndex] );
197
198     //Set the two controls to use the mesh
199     for( int i = 0; i < NUM_MESHES; i++ )
200     {
201       mModels[i].control.SetProperty( Control::Property::BACKGROUND, Property::Value( map ) );
202     }
203   }
204
205   //Rotates the panned model based on the gesture.
206   void OnPan( Actor actor, const PanGesture& gesture )
207   {
208     switch( gesture.state )
209     {
210       case Gesture::Started:
211       {
212         //Find out which model has been selected
213         actor.GetProperty( actor.GetPropertyIndex( "Tag" ) ).Get( mSelectedModelIndex );
214
215         //Pause current animation, as the gesture will be used to manually rotate the model
216         mModels[mSelectedModelIndex].rotationAnimation.Pause();
217
218         break;
219       }
220       case Gesture::Continuing:
221       {
222         //Rotate based off the gesture.
223         mModels[mSelectedModelIndex].rotation.x -= gesture.displacement.y / X_ROTATION_DISPLACEMENT_FACTOR; // Y displacement rotates around X axis
224         mModels[mSelectedModelIndex].rotation.y += gesture.displacement.x / Y_ROTATION_DISPLACEMENT_FACTOR; // X displacement rotates around Y axis
225         Quaternion rotation = Quaternion( Radian( mModels[mSelectedModelIndex].rotation.x ), Vector3::XAXIS) *
226                               Quaternion( Radian( mModels[mSelectedModelIndex].rotation.y ), Vector3::YAXIS);
227
228         mModels[mSelectedModelIndex].control.SetOrientation( rotation );
229
230         break;
231       }
232       case Gesture::Finished:
233       {
234         //Return to automatic animation
235         mModels[mSelectedModelIndex].rotationAnimation.Play();
236
237         break;
238       }
239       case Gesture::Cancelled:
240       {
241         //Return to automatic animation
242         mModels[mSelectedModelIndex].rotationAnimation.Play();
243
244         break;
245       }
246       default:
247       {
248         //We can ignore other gestures and gesture states.
249         break;
250       }
251     }
252   }
253
254   //Cycle through the list of models.
255   bool OnChangeModelClicked( Toolkit::Button button )
256   {
257     ++mModelIndex %= 3;
258
259     ReloadModel();
260
261     return true;
262   }
263
264   //Cycle through the list of shaders.
265   bool OnChangeShaderClicked( Toolkit::Button button )
266   {
267     ++mShaderIndex %= 3;
268
269     ReloadModel();
270
271     return true;
272   }
273
274   //If escape or the back button is pressed, quit the application (and return to the launcher)
275   void OnKeyEvent( const KeyEvent& event )
276   {
277     if( event.state == KeyEvent::Down )
278     {
279       if( IsKey( event, DALI_KEY_ESCAPE) || IsKey( event, DALI_KEY_BACK ) )
280       {
281         mApplication.Quit();
282       }
283     }
284   }
285
286 private:
287   Application&  mApplication;
288
289   //The models displayed on screen, including information about rotation.
290   Model mModels[NUM_MESHES];
291   Actor mContainers[NUM_MESHES];
292
293   //Used to detect panning to rotate the selected model.
294   PanGestureDetector mPanGestureDetector;
295
296   int mModelIndex; //Index of model to load.
297   int mShaderIndex; //Index of shader type to use.
298   int mSelectedModelIndex; //Index of model selected on screen.
299 };
300
301 void RunTest( Application& application )
302 {
303   MeshRendererController test( application );
304
305   application.MainLoop();
306 }
307
308 // Entry point for Linux & Tizen applications
309 //
310 int main( int argc, char **argv )
311 {
312   Application application = Application::New( &argc, &argv );
313
314   RunTest( application );
315
316   return 0;
317 }