Implemented a mesh renderer to display 3D objects from files.
[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.45f;
48
49 } //End namespace
50
51 class SharedMeshRendererController : public ConnectionTracker
52 {
53 public:
54
55   SharedMeshRendererController( Application& application )
56   : mApplication( application ),   //Store handle to the application.
57     mModelIndex( 1 ),              //Start with metal robot.
58     mShaderIndex( 0 ),             //Start with all textures.
59     mSelectedModelIndex( 0 )       //Non-valid default, which will get set to a correct value when used.
60   {
61     // Connect to the Application's Init signal
62     mApplication.InitSignal().Connect( this, &SharedMeshRendererController::Create );
63   }
64
65   ~SharedMeshRendererController()
66   {
67   }
68
69   // The Init signal is received once (only) during the Application lifetime
70   void Create( Application& application )
71   {
72     // Get a handle to the stage
73     Stage stage = Stage::GetCurrent();
74
75     //Add background
76     ImageView backView = ImageView::New( BACKGROUND_IMAGE );
77     backView.SetAnchorPoint( AnchorPoint::TOP_LEFT );
78     stage.Add( backView );
79
80     //Setup and load the 3D models and buttons
81     LoadScene();
82   }
83
84   //Sets up the on-screen elements.
85   void LoadScene()
86   {
87     Stage stage = Stage::GetCurrent();
88
89     //Set up 3D layer to place objects on.
90     Layer layer = Layer::New();
91     layer.SetParentOrigin( ParentOrigin::CENTER );
92     layer.SetAnchorPoint( AnchorPoint::CENTER );
93     layer.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS );
94     layer.SetBehavior( Layer::LAYER_3D );
95     stage.Add( layer );
96
97     //Containers to house each renderer-holding-actor, to provide a constant hitbox for pan detection.
98     Actor container1 = Actor::New();
99     container1.SetResizePolicy( ResizePolicy::SIZE_RELATIVE_TO_PARENT, Dimension::ALL_DIMENSIONS );
100     container1.SetSizeModeFactor( Vector3( MODEL_SCALE, MODEL_SCALE, 0.0f ) );
101     container1.SetParentOrigin( ParentOrigin::CENTER );
102     container1.SetAnchorPoint( AnchorPoint::CENTER );
103     container1.SetPosition( stage.GetSize().width * 0.25, 0.0 ); //Place on right half of screen.
104     container1.RegisterProperty( "Tag", Property::Value( 0 ) ); // Used to identify this actor and index into the model.
105     layer.Add( container1 );
106
107     Actor container2 = Actor::New();
108     container2.SetResizePolicy( ResizePolicy::SIZE_RELATIVE_TO_PARENT, Dimension::ALL_DIMENSIONS );
109     container2.SetSizeModeFactor( Vector3( MODEL_SCALE / 2, MODEL_SCALE / 2, 0.0f ) );
110     container2.SetParentOrigin( ParentOrigin::CENTER );
111     container2.SetAnchorPoint( AnchorPoint::CENTER );
112     container2.SetPosition( stage.GetSize().width * -0.25, 0.0 ); //Place on left half of screen.
113     container2.RegisterProperty( "Tag", Property::Value( 1 ) ); // Used to identify this actor and index into the model.
114     layer.Add( container2 );
115
116     //Attach gesture detector to pan models when rotated.
117     mPanGestureDetector = PanGestureDetector::New();
118     mPanGestureDetector.Attach( container1 );
119     mPanGestureDetector.Attach( container2 );
120     mPanGestureDetector.DetectedSignal().Connect( this, &SharedMeshRendererController::OnPan );
121
122     //Create actors to display meshes.
123     Control control1 = Control::New();
124     control1.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS );
125     control1.SetParentOrigin( ParentOrigin::CENTER );
126     control1.SetAnchorPoint( AnchorPoint::CENTER );
127     container1.Add( control1 );
128
129     Control control2 = Control::New();
130     control2.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS );
131     control2.SetParentOrigin( ParentOrigin::CENTER );
132     control2.SetAnchorPoint( AnchorPoint::CENTER );
133     container2.Add( control2 );
134
135     //Make actors spin to demonstrate 3D.
136     Animation rotationAnimation1 = Animation::New( 15.0f );
137     rotationAnimation1.AnimateBy( Property( control1, Actor::Property::ORIENTATION ),
138                                   Quaternion( Degree( 0.0f ), Degree( 360.0f ), Degree( 0.0f ) ) );
139     rotationAnimation1.SetLooping( true );
140     rotationAnimation1.Play();
141
142     Animation rotationAnimation2 = Animation::New( 15.0f );
143     rotationAnimation2.AnimateBy( Property( control2, Actor::Property::ORIENTATION ),
144                                   Quaternion( Degree( 0.0f ), Degree( -360.0f ), Degree( 0.0f ) ) );
145     rotationAnimation2.SetLooping( true );
146     rotationAnimation2.Play();
147
148     //Store model information in corresponding structs.
149     mModels[0].control = control1;
150     mModels[0].rotation.x = 0.0f;
151     mModels[0].rotation.y = 0.0f;
152     mModels[0].rotationAnimation = rotationAnimation1;
153
154     mModels[1].control = control2;
155     mModels[1].rotation.x = 0.0f;
156     mModels[1].rotation.y = 0.0f;
157     mModels[1].rotationAnimation = rotationAnimation2;
158
159     //Calling this sets the model in the two actors.
160     ReloadModel();
161
162     //Create button for model changing
163     Toolkit::PushButton modelButton = Toolkit::PushButton::New();
164     modelButton.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::ALL_DIMENSIONS );
165     modelButton.ClickedSignal().Connect( this, &SharedMeshRendererController::OnChangeModelClicked );
166     modelButton.SetParentOrigin( Vector3( 0.1, 0.9, 0.5 ) ); //Offset from bottom left
167     modelButton.SetAnchorPoint( AnchorPoint::BOTTOM_LEFT );
168     modelButton.SetLabelText( "Change Model" );
169     layer.Add( modelButton );
170
171     //Create button for shader changing
172     Toolkit::PushButton shaderButton = Toolkit::PushButton::New();
173     shaderButton.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::ALL_DIMENSIONS );
174     shaderButton.ClickedSignal().Connect( this, &SharedMeshRendererController::OnChangeShaderClicked );
175     shaderButton.SetParentOrigin( Vector3( 0.9, 0.9, 0.5 ) ); //Offset from bottom right
176     shaderButton.SetAnchorPoint( AnchorPoint::BOTTOM_RIGHT );
177     shaderButton.SetLabelText( "Change Shader" );
178     layer.Add( shaderButton );
179   }
180
181   //Updates the displayed models to account for parameter changes.
182   void ReloadModel()
183   {
184     //Create mesh property map
185     Property::Map map;
186     map.Insert( "rendererType", "mesh" );
187     map.Insert( "objectUrl", MODEL_FILE[mModelIndex] );
188     map.Insert( "materialUrl", MATERIAL_FILE[mModelIndex] );
189     map.Insert( "texturesPath", TEXTURES_PATH );
190     map.Insert( "shaderType", SHADER_TYPE[mShaderIndex] );
191
192     //Set the two controls to use the mesh
193     mModels[0].control.SetProperty( Control::Property::BACKGROUND, Property::Value( map ) );
194     mModels[1].control.SetProperty( Control::Property::BACKGROUND, Property::Value( map ) );
195   }
196
197   //Rotates the panned model based on the gesture.
198   void OnPan( Actor actor, const PanGesture& gesture )
199   {
200     switch( gesture.state )
201     {
202       case Gesture::Started:
203       {
204         //Find out which model has been selected
205         actor.GetProperty( actor.GetPropertyIndex( "Tag" ) ).Get( mSelectedModelIndex );
206
207         //Pause current animation, as the gesture will be used to manually rotate the model
208         mModels[mSelectedModelIndex].rotationAnimation.Pause();
209
210         break;
211       }
212       case Gesture::Continuing:
213       {
214         //Rotate based off the gesture.
215         mModels[mSelectedModelIndex].rotation.x -= gesture.displacement.y / X_ROTATION_DISPLACEMENT_FACTOR; // Y displacement rotates around X axis
216         mModels[mSelectedModelIndex].rotation.y += gesture.displacement.x / Y_ROTATION_DISPLACEMENT_FACTOR; // X displacement rotates around Y axis
217         Quaternion rotation = Quaternion( Radian( mModels[mSelectedModelIndex].rotation.x ), Vector3::XAXIS) *
218                               Quaternion( Radian( mModels[mSelectedModelIndex].rotation.y ), Vector3::YAXIS);
219
220         mModels[mSelectedModelIndex].control.SetOrientation( rotation );
221
222         break;
223       }
224       case Gesture::Finished:
225       {
226         //Return to automatic animation
227         mModels[mSelectedModelIndex].rotationAnimation.Play();
228
229         break;
230       }
231       case Gesture::Cancelled:
232       {
233         //Return to automatic animation
234         mModels[mSelectedModelIndex].rotationAnimation.Play();
235
236         break;
237       }
238       default:
239       {
240         //We can ignore other gestures and gesture states.
241         break;
242       }
243     }
244   }
245
246   //Cycle through the list of models.
247   bool OnChangeModelClicked( Toolkit::Button button )
248   {
249     ++mModelIndex %= 3;
250
251     ReloadModel();
252
253     return true;
254   }
255
256   //Cycle through the list of shaders.
257   bool OnChangeShaderClicked( Toolkit::Button button )
258   {
259     ++mShaderIndex %= 3;
260
261     ReloadModel();
262
263     return true;
264   }
265
266 private:
267   Application&  mApplication;
268
269   //The models displayed on screen, including information about rotation.
270   Model mModels[2];
271
272   //Used to detect panning to rotate the selected model.
273   PanGestureDetector mPanGestureDetector;
274
275   int mModelIndex; //Index of model to load.
276   int mShaderIndex; //Index of shader type to use.
277   int mSelectedModelIndex; //Index of model selected on screen.
278 };
279
280 void RunTest( Application& application )
281 {
282   SharedMeshRendererController test( application );
283
284   application.MainLoop();
285 }
286
287 // Entry point for Linux & Tizen applications
288 //
289 int main( int argc, char **argv )
290 {
291   Application application = Application::New( &argc, &argv );
292
293   RunTest( application );
294
295   return 0;
296 }