1 #include <dali-toolkit/dali-toolkit.h>
2 #include <dali/public-api/object/property-map.h>
5 using namespace Dali::Toolkit;
9 //Keeps information about each model for access.
12 Control control; // Control housing the mesh visual 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.
18 const char * const MODEL_FILE_TABLE[] =
20 DEMO_MODEL_DIR "Dino.obj",
21 DEMO_MODEL_DIR "ToyRobot-Metal.obj",
22 DEMO_MODEL_DIR "Toyrobot-Plastic.obj"
25 const char * const MATERIAL_FILE_TABLE[] =
27 DEMO_MODEL_DIR "Dino.mtl",
28 DEMO_MODEL_DIR "ToyRobot-Metal.mtl",
29 DEMO_MODEL_DIR "Toyrobot-Plastic.mtl"
32 const char * const TEXTURES_PATH( DEMO_IMAGE_DIR "" );
34 //Possible shading modes.
35 MeshVisual::ShadingMode::Value SHADING_MODE_TABLE[] =
37 MeshVisual::ShadingMode::TEXTURED_WITH_DETAILED_SPECULAR_LIGHTING,
38 MeshVisual::ShadingMode::TEXTURED_WITH_SPECULAR_LIGHTING,
39 MeshVisual::ShadingMode::TEXTURELESS_WITH_DIFFUSE_LIGHTING
43 const char * const PAUSE = " || ";
44 const char * const PLAY = " > ";
45 const char * const FIXED = "FIXED";
46 const char * const MANUAL = "MANUAL";
47 const char * const FRONT = "FRONT";
48 const char * const BACK = "BACK";
50 //Image urls for the light.
51 const char * const LIGHT_URL_FRONT = DEMO_IMAGE_DIR "light-icon-front.png";
52 const char * const LIGHT_URL_BACK = DEMO_IMAGE_DIR "light-icon-back.png";
54 const float X_ROTATION_DISPLACEMENT_FACTOR = 60.0f;
55 const float Y_ROTATION_DISPLACEMENT_FACTOR = 60.0f;
56 const float MODEL_SCALE = 0.75f;
57 const float LIGHT_SCALE = 0.15f;
58 const float BUTTONS_OFFSET_BOTTOM = 0.08f;
59 const float BUTTONS_OFFSET_SIDE = 0.2f;
60 const int NUM_MESHES = 2;
62 //Used to identify actors.
63 const int MODEL_TAG = 0;
64 const int LIGHT_TAG = 1;
65 const int LAYER_TAG = 2;
69 class MeshVisualController : public ConnectionTracker
73 MeshVisualController( Application& application )
74 : mApplication( application ), //Store handle to the application.
75 mModelIndex( 1 ), //Start with metal robot.
76 mShadingModeIndex( 0 ), //Start with texture and detailed specular lighting.
77 mTag( -1 ), //Non-valid default, which will get set to a correct value when used.
78 mSelectedModelIndex( -1 ), //Non-valid default, which will get set to a correct value when used.
79 mPaused( false ), //Animations play by default.
80 mLightFixed( true ), //The light is fixed by default.
81 mLightFront( true ) //The light is in front by default.
83 // Connect to the Application's Init signal
84 mApplication.InitSignal().Connect( this, &MeshVisualController::Create );
87 ~MeshVisualController()
91 // The Init signal is received once (only) during the Application lifetime
92 void Create( Application& application )
94 // Get a handle to the stage
95 Stage stage = Stage::GetCurrent();
96 stage.SetBackgroundColor( Vector4( 0.0, 0.5, 1.0, 1.0 ) );
98 //Set up layer to place objects on.
99 Layer baseLayer = Layer::New();
100 baseLayer.SetParentOrigin( ParentOrigin::CENTER );
101 baseLayer.SetAnchorPoint( AnchorPoint::CENTER );
102 baseLayer.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS );
103 baseLayer.SetBehavior( Layer::LAYER_2D ); //We use a 2D layer as this is closer to UI work than full 3D scene creation.
104 baseLayer.SetDepthTestDisabled( false ); //Enable depth testing, as otherwise the 2D layer would not do so.
105 baseLayer.RegisterProperty( "Tag", LAYER_TAG ); //Used to differentiate between different kinds of actor.
106 baseLayer.TouchedSignal().Connect( this, &MeshVisualController::OnTouch );
107 stage.Add( baseLayer );
109 //Place models on the scene.
110 SetupModels( baseLayer );
112 //Place buttons on the scene.
113 SetupButtons( baseLayer );
115 //Add a light to the scene.
116 SetupLight( baseLayer );
118 //Allow for exiting of the application via key presses.
119 stage.KeyEventSignal().Connect( this, &MeshVisualController::OnKeyEvent );
122 //Loads and adds the models to the scene, inside containers for hit detection.
123 void SetupModels( Layer layer )
125 //Add containers to house each renderer-holding-actor.
126 for( int i = 0; i < NUM_MESHES; i++ )
128 mContainers[i] = Actor::New();
129 mContainers[i].SetResizePolicy( ResizePolicy::SIZE_RELATIVE_TO_PARENT, Dimension::ALL_DIMENSIONS );
130 mContainers[i].RegisterProperty( "Tag", MODEL_TAG ); //Used to differentiate between different kinds of actor.
131 mContainers[i].RegisterProperty( "Model", Property::Value( i ) ); //Used to index into the model.
132 mContainers[i].TouchedSignal().Connect( this, &MeshVisualController::OnTouch );
133 layer.Add( mContainers[i] );
136 //Position each container individually on screen
138 //Main, central model
139 mContainers[0].SetSizeModeFactor( Vector3( MODEL_SCALE, MODEL_SCALE, 0.0f ) );
140 mContainers[0].SetParentOrigin( ParentOrigin::CENTER );
141 mContainers[0].SetAnchorPoint( AnchorPoint::CENTER );
144 mContainers[1].SetSizeModeFactor( Vector3( MODEL_SCALE / 3.0f, MODEL_SCALE / 3.0f, 0.0f ) );
145 mContainers[1].SetParentOrigin( Vector3( 0.05, 0.03, 0.5 ) ); //Offset from top left
146 mContainers[1].SetAnchorPoint( AnchorPoint::TOP_LEFT );
149 for( int i = 0; i < NUM_MESHES; i++ )
151 //Create control to display model
152 Control control = Control::New();
153 control.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS );
154 control.SetParentOrigin( ParentOrigin::CENTER );
155 control.SetAnchorPoint( AnchorPoint::CENTER );
156 mContainers[i].Add( control );
158 //Make model spin to demonstrate 3D
159 Animation rotationAnimation = Animation::New( 15.0f );
160 float spin = i % 2 == 0 ? 1.0f : -1.0f; //Make actors spin in different directions to better show independence.
161 rotationAnimation.AnimateBy( Property( control, Actor::Property::ORIENTATION ),
162 Quaternion( Degree( 0.0f ), Degree( spin * 360.0f ), Degree( 0.0f ) ) );
163 rotationAnimation.SetLooping( true );
164 rotationAnimation.Play();
166 //Store model information in corresponding structs.
167 mModels[i].control = control;
168 mModels[i].rotation.x = 0.0f;
169 mModels[i].rotation.y = 0.0f;
170 mModels[i].rotationAnimation = rotationAnimation;
173 //Calling this sets the model in the controls.
177 //Place the various buttons on the bottom of the screen, with title labels where necessary.
178 void SetupButtons( Layer layer )
180 //Actor for positioning model and shading mode buttons.
181 Actor positionActorModel = Actor::New();
182 positionActorModel.SetParentOrigin( Vector3( BUTTONS_OFFSET_SIDE, 1.0 - BUTTONS_OFFSET_BOTTOM, 0.5 ) );
183 positionActorModel.SetAnchorPoint( AnchorPoint::BOTTOM_CENTER );
184 layer.Add( positionActorModel );
186 //Create button for model changing.
187 PushButton modelButton = Toolkit::PushButton::New();
188 modelButton.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::ALL_DIMENSIONS );
189 modelButton.ClickedSignal().Connect( this, &MeshVisualController::OnChangeModelClicked );
190 modelButton.SetParentOrigin( ParentOrigin::TOP_CENTER );
191 modelButton.SetAnchorPoint( AnchorPoint::BOTTOM_CENTER );
192 modelButton.SetLabelText( "Model" );
193 positionActorModel.Add( modelButton );
195 //Create button for shading mode changing.
196 PushButton shadingModeButton = Toolkit::PushButton::New();
197 shadingModeButton.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::ALL_DIMENSIONS );
198 shadingModeButton.ClickedSignal().Connect( this, &MeshVisualController::OnChangeShadingModeClicked );
199 shadingModeButton.SetParentOrigin( ParentOrigin::BOTTOM_CENTER );
200 shadingModeButton.SetAnchorPoint( AnchorPoint::TOP_CENTER );
201 shadingModeButton.SetLabelText( "Shading Mode" );
202 positionActorModel.Add( shadingModeButton );
204 //Text label title for changing model or shading mode.
205 TextLabel changeTitleLabel = TextLabel::New( "Change" );
206 changeTitleLabel.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::ALL_DIMENSIONS );
207 changeTitleLabel.SetProperty( TextLabel::Property::UNDERLINE, "{\"thickness\":\"2.0\"}" );
208 changeTitleLabel.SetParentOrigin( ParentOrigin::TOP_CENTER );
209 changeTitleLabel.SetAnchorPoint( AnchorPoint::BOTTOM_CENTER );
210 modelButton.Add( changeTitleLabel );
212 //Create button for pausing animations.
213 PushButton pauseButton = Toolkit::PushButton::New();
214 pauseButton.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::ALL_DIMENSIONS );
215 pauseButton.ClickedSignal().Connect( this, &MeshVisualController::OnPauseClicked );
216 pauseButton.SetParentOrigin( Vector3( 0.5, 1.0 - BUTTONS_OFFSET_BOTTOM, 0.5 ) );
217 pauseButton.SetAnchorPoint( AnchorPoint::CENTER );
218 pauseButton.SetLabelText( PAUSE );
219 layer.Add( pauseButton );
221 //Actor for positioning light position buttons.
222 Actor positionActorLight = Actor::New();
223 positionActorLight.SetParentOrigin( Vector3( 1.0 - BUTTONS_OFFSET_SIDE, 1.0 - BUTTONS_OFFSET_BOTTOM, 0.5 ) );
224 positionActorLight.SetAnchorPoint( AnchorPoint::BOTTOM_CENTER );
225 layer.Add( positionActorLight );
227 //Create button for switching between manual and fixed light position.
228 PushButton lightModeButton = Toolkit::PushButton::New();
229 lightModeButton.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::ALL_DIMENSIONS );
230 lightModeButton.ClickedSignal().Connect( this, &MeshVisualController::OnChangeLightModeClicked );
231 lightModeButton.SetParentOrigin( ParentOrigin::TOP_CENTER );
232 lightModeButton.SetAnchorPoint( AnchorPoint::BOTTOM_CENTER );
233 lightModeButton.SetLabelText( FIXED );
234 positionActorLight.Add( lightModeButton );
236 //Create button for switching between front and back light position.
237 PushButton lightSideButton = Toolkit::PushButton::New();
238 lightSideButton.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::ALL_DIMENSIONS );
239 lightSideButton.ClickedSignal().Connect( this, &MeshVisualController::OnChangeLightSideClicked );
240 lightSideButton.SetParentOrigin( ParentOrigin::BOTTOM_CENTER );
241 lightSideButton.SetAnchorPoint( AnchorPoint::TOP_CENTER );
242 lightSideButton.SetLabelText( FRONT );
243 positionActorLight.Add( lightSideButton );
245 //Text label title for light position mode.
246 TextLabel lightTitleLabel = TextLabel::New( "Light Position" );
247 lightTitleLabel.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::ALL_DIMENSIONS );
248 lightTitleLabel.SetProperty( TextLabel::Property::UNDERLINE, "{\"thickness\":\"2.0\"}" );
249 lightTitleLabel.SetParentOrigin( ParentOrigin::TOP_CENTER );
250 lightTitleLabel.SetAnchorPoint( AnchorPoint::BOTTOM_CENTER );
251 lightModeButton.Add( lightTitleLabel );
254 //Add a point light source the the scene, on a layer above the first.
255 void SetupLight( Layer baseLayer )
257 //Create control to act as light source of scene.
258 mLightSource = Control::New();
259 mLightSource.RegisterProperty( "Tag", LIGHT_TAG );
261 //Set size of control based on screen dimensions.
262 Stage stage = Stage::GetCurrent();
263 if( stage.GetSize().width < stage.GetSize().height )
266 mLightSource.SetResizePolicy( ResizePolicy::SIZE_RELATIVE_TO_PARENT, Dimension::WIDTH );
267 mLightSource.SetResizePolicy( ResizePolicy::DIMENSION_DEPENDENCY, Dimension::HEIGHT );
268 mLightSource.SetSizeModeFactor( Vector3( LIGHT_SCALE, 0.0f, 0.0f ) );
273 mLightSource.SetResizePolicy( ResizePolicy::SIZE_RELATIVE_TO_PARENT, Dimension::HEIGHT );
274 mLightSource.SetResizePolicy( ResizePolicy::DIMENSION_DEPENDENCY, Dimension::WIDTH );
275 mLightSource.SetSizeModeFactor( Vector3( 0.0f, LIGHT_SCALE, 0.0f ) );
278 //Set position relative to top left, as the light source property is also relative to the top left.
279 mLightSource.SetParentOrigin( ParentOrigin::TOP_LEFT );
280 mLightSource.SetAnchorPoint( AnchorPoint::CENTER );
281 mLightSource.SetPosition( Stage::GetCurrent().GetSize().x * 0.85f, Stage::GetCurrent().GetSize().y * 0.125 );
283 //Supply an image to represent the light.
286 //Connect to touch signal for dragging.
287 mLightSource.TouchedSignal().Connect( this, &MeshVisualController::OnTouch );
289 //Place the light source on a layer above the base, so that it is rendered above everything else.
290 Layer upperLayer = Layer::New();
291 upperLayer.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS );
292 upperLayer.SetParentOrigin( ParentOrigin::CENTER );
293 upperLayer.SetAnchorPoint( AnchorPoint::CENTER );
295 baseLayer.Add( upperLayer );
296 upperLayer.Add( mLightSource );
298 //Decide which light to use to begin with.
302 //Sets the image to use for the light source depending on whether the light is in front or behind.
305 std::string imageUrl;
309 imageUrl = LIGHT_URL_FRONT;
313 imageUrl = LIGHT_URL_BACK;
316 Property::Map lightMap;
317 lightMap.Insert( Visual::Property::TYPE, Visual::IMAGE );
318 lightMap.Insert( ImageVisual::Property::URL, imageUrl );
319 mLightSource.SetProperty( Control::Property::BACKGROUND, Property::Value( lightMap ) );
322 //Updates the displayed models to account for parameter changes.
325 //Create mesh property map
327 map.Insert( Visual::Property::TYPE, Visual::MESH );
328 map.Insert( MeshVisual::Property::OBJECT_URL, MODEL_FILE_TABLE[mModelIndex] );
329 map.Insert( MeshVisual::Property::MATERIAL_URL, MATERIAL_FILE_TABLE[mModelIndex] );
330 map.Insert( MeshVisual::Property::TEXTURES_PATH, TEXTURES_PATH );
331 map.Insert( MeshVisual::Property::SHADING_MODE, SHADING_MODE_TABLE[mShadingModeIndex] );
333 //Set the two controls to use the mesh
334 for( int i = 0; i < NUM_MESHES; i++ )
336 mModels[i].control.SetProperty( Control::Property::BACKGROUND, Property::Value( map ) );
340 //Set the mode used to light the models.
353 //Make the models use a fixed, invisible light above the center of the stage.
356 //Hide draggable source
357 mLightSource.SetVisible( false );
359 //Use stage dimensions to place light at center, offset in z axis.
360 Stage stage = Stage::GetCurrent();
361 float width = stage.GetSize().width;
362 float height = stage.GetSize().height;
363 Vector3 lightPosition = Vector3( width / 2.0f, height / 2.0f,
364 ( mLightFront ? 1 : -1 ) * std::max( width, height ) * 5.0f );
366 //Set global light position
367 for( int i = 0; i < NUM_MESHES; ++i )
369 mModels[i].control.RegisterProperty( "lightPosition", lightPosition, Property::ANIMATABLE );
373 //Make the models use a light source that the user can drag around.
374 void UseManualLight()
376 //Show draggable source
377 mLightSource.SetVisible( true );
379 //Update to switch light position of models to that of the source.
383 //Updates the light position for each model to account for changes in the source on screen.
386 //Set light position to the x and y of the light control, offset into/out of the screen.
387 Vector3 controlPosition = mLightSource.GetCurrentPosition();
388 Vector3 lightPosition = Vector3( controlPosition.x, controlPosition.y,
389 ( mLightFront ? 1 : -1 ) * Stage::GetCurrent().GetSize().x / 2.0f );
391 for( int i = 0; i < NUM_MESHES; ++i )
393 mModels[i].control.RegisterProperty( "lightPosition", lightPosition, Property::ANIMATABLE );
397 //If the light source is touched, move it by dragging it.
398 //If a model is touched, rotate it by panning around.
399 bool OnTouch( Actor actor, const TouchEvent& event )
401 //Get primary touch point.
402 const Dali::TouchPoint& point = event.GetPoint( 0 );
404 switch( point.state )
406 case TouchPoint::Down:
408 //Determine what was touched.
409 actor.GetProperty( actor.GetPropertyIndex( "Tag" ) ).Get( mTag );
411 if( mTag == MODEL_TAG )
413 //Find out which model has been selected
414 actor.GetProperty( actor.GetPropertyIndex( "Model" ) ).Get( mSelectedModelIndex );
416 //Pause current animation, as the touch gesture will be used to manually rotate the model
417 mModels[mSelectedModelIndex].rotationAnimation.Pause();
419 //Store start points.
420 mPanStart = point.screen;
421 mRotationStart = mModels[mSelectedModelIndex].rotation;
426 case TouchPoint::Motion:
428 //Switch on the kind of actor we're interacting with.
431 case MODEL_TAG: //Rotate model
433 //Calculate displacement and corresponding rotation.
434 Vector2 displacement = point.screen - mPanStart;
435 mModels[mSelectedModelIndex].rotation = Vector2( mRotationStart.x - displacement.y / Y_ROTATION_DISPLACEMENT_FACTOR, // Y displacement rotates around X axis
436 mRotationStart.y + displacement.x / X_ROTATION_DISPLACEMENT_FACTOR ); // X displacement rotates around Y axis
437 Quaternion rotation = Quaternion( Radian( mModels[mSelectedModelIndex].rotation.x ), Vector3::XAXIS) *
438 Quaternion( Radian( mModels[mSelectedModelIndex].rotation.y ), Vector3::YAXIS);
441 mModels[mSelectedModelIndex].control.SetOrientation( rotation );
445 case LIGHT_TAG: //Drag light
447 //Set light source to new position and update the models accordingly.
448 mLightSource.SetPosition( Vector3( point.screen ) );
457 case TouchPoint::Interrupted: //Same as finished.
458 case TouchPoint::Finished:
460 if( mTag == MODEL_TAG )
462 //Return to automatic animation
465 mModels[mSelectedModelIndex].rotationAnimation.Play();
473 //Other touch states do nothing.
481 //Cycle through the list of models.
482 bool OnChangeModelClicked( Toolkit::Button button )
491 //Cycle through the list of shading modes.
492 bool OnChangeShadingModeClicked( Toolkit::Button button )
494 ++mShadingModeIndex %= 3;
501 //Pause all animations, and keep them paused even after user panning.
502 //This button is a toggle, so pressing again will start the animations again.
503 bool OnPauseClicked( Toolkit::Button button )
505 //Toggle pause state.
508 //If we wish to pause animations, do so and keep them paused.
511 for( int i = 0; i < NUM_MESHES ; ++i )
513 mModels[i].rotationAnimation.Pause();
516 button.SetLabelText( PLAY );
518 else //Unpause all animations again.
520 for( int i = 0; i < NUM_MESHES ; ++i )
522 mModels[i].rotationAnimation.Play();
525 button.SetLabelText( PAUSE );
532 //Switch between a fixed light source above/behind the screen, and a light source the user can drag around.
533 bool OnChangeLightModeClicked( Toolkit::Button button )
536 mLightFixed = !mLightFixed;
540 button.SetLabelText( FIXED );
544 button.SetLabelText( MANUAL );
552 //Switch between the light being in front of and behind the models.
553 bool OnChangeLightSideClicked( Toolkit::Button button )
556 mLightFront = !mLightFront;
560 button.SetLabelText( FRONT );
564 button.SetLabelText( BACK );
567 //Change light image.
570 //Update light to account for the change.
576 //If escape or the back button is pressed, quit the application (and return to the launcher)
577 void OnKeyEvent( const KeyEvent& event )
579 if( event.state == KeyEvent::Down )
581 if( IsKey( event, DALI_KEY_ESCAPE) || IsKey( event, DALI_KEY_BACK ) )
589 Application& mApplication;
591 //The models displayed on screen, including information about rotation.
592 Model mModels[NUM_MESHES];
593 Actor mContainers[NUM_MESHES];
595 //Acts as a global light source, which can be dragged around.
596 Control mLightSource;
598 //Used to detect panning to rotate the selected model.
600 Vector2 mRotationStart;
602 int mModelIndex; //Index of model to load.
603 int mShadingModeIndex; //Index of shading mode to use.
604 int mTag; //Identifies what kind of actor has been selected in OnTouch.
605 int mSelectedModelIndex; //Index of model selected on screen.
606 bool mPaused; //If true, all animations are paused and should stay so.
607 bool mLightFixed; //If false, the light is in manual.
608 bool mLightFront; //Bool for light being in front or behind the models.
611 // Entry point for Linux & Tizen applications
613 int main( int argc, char **argv )
615 Application application = Application::New( &argc, &argv );
616 MeshVisualController test( application );
617 application.MainLoop();