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 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.
18 const char * const MODEL_FILE[] =
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[] =
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 shader options.
35 const char * const SHADER_TYPE[] =
42 //Files for background and toolbar
43 const char * const BACKGROUND_IMAGE( DEMO_IMAGE_DIR "background-1.jpg");
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;
50 //Used to identify actors.
51 const int MODEL_TAG = 0;
52 const int LIGHT_TAG = 1;
53 const int LAYER_TAG = 2;
57 class MeshRendererController : public ConnectionTracker
61 MeshRendererController( Application& application )
62 : mApplication( application ), //Store handle to the application.
63 mModelIndex( 1 ), //Start with metal robot.
64 mShaderIndex( 0 ), //Start with all textures.
65 mTag( -1 ), //Non-valid default, which will get set to a correct value when used.
66 mSelectedModelIndex( -1 ), //Non-valid default, which will get set to a correct value when used.
67 mPaused( false ) //Animations play by default.
69 // Connect to the Application's Init signal
70 mApplication.InitSignal().Connect( this, &MeshRendererController::Create );
73 ~MeshRendererController()
77 // The Init signal is received once (only) during the Application lifetime
78 void Create( Application& application )
80 // Get a handle to the stage
81 Stage stage = Stage::GetCurrent();
84 ImageView backView = ImageView::New( BACKGROUND_IMAGE );
85 backView.SetAnchorPoint( AnchorPoint::TOP_LEFT );
86 stage.Add( backView );
88 //Setup and load the 3D models and buttons
91 //Allow for exiting of the application via key presses.
92 stage.KeyEventSignal().Connect( this, &MeshRendererController::OnKeyEvent );
95 //Sets up the on-screen elements.
98 Stage stage = Stage::GetCurrent();
100 //Set up layer to place objects on.
101 Layer baseLayer = Layer::New();
102 baseLayer.SetParentOrigin( ParentOrigin::CENTER );
103 baseLayer.SetAnchorPoint( AnchorPoint::CENTER );
104 baseLayer.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS );
105 baseLayer.SetBehavior( Layer::LAYER_2D ); //We use a 2D layer as this is closer to UI work than full 3D scene creation.
106 baseLayer.SetDepthTestDisabled( false ); //Enable depth testing, as otherwise the 2D layer would not do so.
107 baseLayer.RegisterProperty( "Tag", LAYER_TAG ); //Used to differentiate between different kinds of actor.
108 baseLayer.TouchedSignal().Connect( this, &MeshRendererController::OnTouch );
109 stage.Add( baseLayer );
111 //Add containers to house each renderer-holding-actor.
112 for( int i = 0; i < NUM_MESHES; i++ )
114 mContainers[i] = Actor::New();
115 mContainers[i].SetResizePolicy( ResizePolicy::SIZE_RELATIVE_TO_PARENT, Dimension::ALL_DIMENSIONS );
116 mContainers[i].RegisterProperty( "Tag", MODEL_TAG ); //Used to differentiate between different kinds of actor.
117 mContainers[i].RegisterProperty( "Model", Property::Value( i ) ); //Used to index into the model.
119 //Position each container on screen
122 //Main, central model
123 mContainers[i].SetSizeModeFactor( Vector3( MODEL_SCALE, MODEL_SCALE, 0.0f ) );
124 mContainers[i].SetParentOrigin( ParentOrigin::CENTER );
125 mContainers[i].SetAnchorPoint( AnchorPoint::CENTER );
130 mContainers[i].SetSizeModeFactor( Vector3( MODEL_SCALE / 3.0f, MODEL_SCALE / 3.0f, 0.0f ) );
131 mContainers[i].SetParentOrigin( Vector3( 0.05, 0.03, 0.5 ) ); //Offset from top left
132 mContainers[i].SetAnchorPoint( AnchorPoint::TOP_LEFT );
137 mContainers[i].SetSizeModeFactor( Vector3( MODEL_SCALE / 3.0f, MODEL_SCALE / 3.0f, 0.0f ) );
138 mContainers[i].SetParentOrigin( Vector3( 0.95, 0.03, 0.5 ) ); //Offset from top right
139 mContainers[i].SetAnchorPoint( AnchorPoint::TOP_RIGHT );
142 mContainers[i].TouchedSignal().Connect( this, &MeshRendererController::OnTouch );
143 baseLayer.Add( mContainers[i] );
147 for( int i = 0; i < NUM_MESHES; i++ )
149 //Create control to display model
150 Control control = Control::New();
151 control.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS );
152 control.SetParentOrigin( ParentOrigin::CENTER );
153 control.SetAnchorPoint( AnchorPoint::CENTER );
154 mContainers[i].Add( control );
156 //Make model spin to demonstrate 3D
157 Animation rotationAnimation = Animation::New( 15.0f );
158 float spin = i % 2 == 0 ? 1.0f : -1.0f; //Make actors spin in different directions to better show independence.
159 rotationAnimation.AnimateBy( Property( control, Actor::Property::ORIENTATION ),
160 Quaternion( Degree( 0.0f ), Degree( spin * 360.0f ), Degree( 0.0f ) ) );
161 rotationAnimation.SetLooping( true );
162 rotationAnimation.Play();
164 //Store model information in corresponding structs.
165 mModels[i].control = control;
166 mModels[i].rotation.x = 0.0f;
167 mModels[i].rotation.y = 0.0f;
168 mModels[i].rotationAnimation = rotationAnimation;
171 //Calling this sets the model in the controls.
174 //Create button for model changing
175 Toolkit::PushButton modelButton = Toolkit::PushButton::New();
176 modelButton.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::ALL_DIMENSIONS );
177 modelButton.ClickedSignal().Connect( this, &MeshRendererController::OnChangeModelClicked );
178 modelButton.SetParentOrigin( Vector3( 0.05, 0.95, 0.5 ) ); //Offset from bottom left
179 modelButton.SetAnchorPoint( AnchorPoint::BOTTOM_LEFT );
180 modelButton.SetLabelText( "Change Model" );
181 baseLayer.Add( modelButton );
183 //Create button for shader changing
184 Toolkit::PushButton shaderButton = Toolkit::PushButton::New();
185 shaderButton.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::ALL_DIMENSIONS );
186 shaderButton.ClickedSignal().Connect( this, &MeshRendererController::OnChangeShaderClicked );
187 shaderButton.SetParentOrigin( Vector3( 0.95, 0.95, 0.5 ) ); //Offset from bottom right
188 shaderButton.SetAnchorPoint( AnchorPoint::BOTTOM_RIGHT );
189 shaderButton.SetLabelText( "Change Shader" );
190 baseLayer.Add( shaderButton );
192 //Create button for pausing animations
193 Toolkit::PushButton pauseButton = Toolkit::PushButton::New();
194 pauseButton.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::ALL_DIMENSIONS );
195 pauseButton.ClickedSignal().Connect( this, &MeshRendererController::OnPauseClicked );
196 pauseButton.SetParentOrigin( Vector3( 0.5, 0.95, 0.5 ) ); //Offset from bottom center
197 pauseButton.SetAnchorPoint( AnchorPoint::BOTTOM_CENTER );
198 pauseButton.SetLabelText( " || " );
199 baseLayer.Add( pauseButton );
201 //Create control to act as light source of scene.
202 mLightSource = Control::New();
203 mLightSource.SetResizePolicy( ResizePolicy::FIT_TO_CHILDREN, Dimension::WIDTH );
204 mLightSource.SetResizePolicy( ResizePolicy::DIMENSION_DEPENDENCY, Dimension::HEIGHT );
205 mLightSource.RegisterProperty( "Tag", LIGHT_TAG );
207 //Set position relative to top left, as the light source property is also relative to the top left.
208 mLightSource.SetParentOrigin( ParentOrigin::TOP_LEFT );
209 mLightSource.SetAnchorPoint( AnchorPoint::CENTER );
210 mLightSource.SetPosition( Stage::GetCurrent().GetSize().x * 0.5f, Stage::GetCurrent().GetSize().y * 0.1f );
212 //Make white background.
213 Property::Map lightMap;
214 lightMap.Insert( "rendererType", "COLOR" );
215 lightMap.Insert( "mixColor", Color::WHITE );
216 mLightSource.SetProperty( Control::Property::BACKGROUND, Property::Value( lightMap ) );
218 //Label to show what this actor is for the user.
219 TextLabel lightLabel = TextLabel::New( "Light" );
220 lightLabel.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::ALL_DIMENSIONS );
221 lightLabel.SetParentOrigin( ParentOrigin::CENTER );
222 lightLabel.SetAnchorPoint( AnchorPoint::CENTER );
223 float padding = 5.0f;
224 lightLabel.SetPadding( Padding( padding, padding, padding, padding ) );
225 mLightSource.Add( lightLabel );
227 //Connect to touch signal for dragging.
228 mLightSource.TouchedSignal().Connect( this, &MeshRendererController::OnTouch );
230 //Place the light source on a layer above the base, so that it is rendered above everything else.
231 Layer upperLayer = Layer::New();
232 baseLayer.Add( upperLayer );
233 upperLayer.Add( mLightSource );
235 //Calling this sets the light position of each model to that of the light source control.
239 //Updates the displayed models to account for parameter changes.
242 //Create mesh property map
244 map.Insert( "rendererType", "MESH" );
245 map.Insert( "objectUrl", MODEL_FILE[mModelIndex] );
246 map.Insert( "materialUrl", MATERIAL_FILE[mModelIndex] );
247 map.Insert( "texturesPath", TEXTURES_PATH );
248 map.Insert( "shaderType", SHADER_TYPE[mShaderIndex] );
249 map.Insert( "useSoftNormals", false );
251 //Set the two controls to use the mesh
252 for( int i = 0; i < NUM_MESHES; i++ )
254 mModels[i].control.SetProperty( Control::Property::BACKGROUND, Property::Value( map ) );
258 //Updates the light position for each model to account for changes in the source on screen.
261 //Set light position to the x and y of the light control, offset out of the screen.
262 Vector3 controlPosition = mLightSource.GetCurrentPosition();
263 Vector3 lightPosition = Vector3( controlPosition.x, controlPosition.y, Stage::GetCurrent().GetSize().x * 2.0f );
265 for( int i = 0; i < NUM_MESHES; ++i )
267 mModels[i].control.RegisterProperty( "lightPosition", lightPosition, Property::ANIMATABLE );
271 //If the light source is touched, move it by dragging it.
272 //If a model is touched, rotate it by panning around.
273 bool OnTouch( Actor actor, const TouchEvent& event )
275 //Get primary touch point.
276 const Dali::TouchPoint& point = event.GetPoint( 0 );
278 switch( point.state )
280 case TouchPoint::Down:
282 //Determine what was touched.
283 actor.GetProperty( actor.GetPropertyIndex( "Tag" ) ).Get( mTag );
285 if( mTag == MODEL_TAG )
287 //Find out which model has been selected
288 actor.GetProperty( actor.GetPropertyIndex( "Model" ) ).Get( mSelectedModelIndex );
290 //Pause current animation, as the touch gesture will be used to manually rotate the model
291 mModels[mSelectedModelIndex].rotationAnimation.Pause();
293 //Store start points.
294 mPanStart = point.screen;
295 mRotationStart = mModels[mSelectedModelIndex].rotation;
300 case TouchPoint::Motion:
302 //Switch on the kind of actor we're interacting with.
305 case MODEL_TAG: //Rotate model
307 //Calculate displacement and corresponding rotation.
308 Vector2 displacement = point.screen - mPanStart;
309 mModels[mSelectedModelIndex].rotation = Vector2( mRotationStart.x - displacement.y / Y_ROTATION_DISPLACEMENT_FACTOR, // Y displacement rotates around X axis
310 mRotationStart.y + displacement.x / X_ROTATION_DISPLACEMENT_FACTOR ); // X displacement rotates around Y axis
311 Quaternion rotation = Quaternion( Radian( mModels[mSelectedModelIndex].rotation.x ), Vector3::XAXIS) *
312 Quaternion( Radian( mModels[mSelectedModelIndex].rotation.y ), Vector3::YAXIS);
315 mModels[mSelectedModelIndex].control.SetOrientation( rotation );
319 case LIGHT_TAG: //Drag light
321 //Set light source to new position and update the models accordingly.
322 mLightSource.SetPosition( Vector3( point.screen ) );
331 case TouchPoint::Interrupted: //Same as finished.
332 case TouchPoint::Finished:
334 if( mTag == MODEL_TAG )
336 //Return to automatic animation
339 mModels[mSelectedModelIndex].rotationAnimation.Play();
347 //Other touch states do nothing.
355 //Cycle through the list of models.
356 bool OnChangeModelClicked( Toolkit::Button button )
365 //Cycle through the list of shaders.
366 bool OnChangeShaderClicked( Toolkit::Button button )
375 //Pause all animations, and keep them paused even after user panning.
376 //This button is a toggle, so pressing again will start the animations again.
377 bool OnPauseClicked( Toolkit::Button button )
379 //Toggle pause state.
382 //If we wish to pause animations, do so and keep them paused.
385 for( int i = 0; i < NUM_MESHES ; ++i )
387 mModels[i].rotationAnimation.Pause();
390 button.SetLabelText( " > " );
392 else //Unpause all animations again.
394 for( int i = 0; i < NUM_MESHES ; ++i )
396 mModels[i].rotationAnimation.Play();
399 button.SetLabelText( " || " );
405 //If escape or the back button is pressed, quit the application (and return to the launcher)
406 void OnKeyEvent( const KeyEvent& event )
408 if( event.state == KeyEvent::Down )
410 if( IsKey( event, DALI_KEY_ESCAPE) || IsKey( event, DALI_KEY_BACK ) )
418 Application& mApplication;
420 //The models displayed on screen, including information about rotation.
421 Model mModels[NUM_MESHES];
422 Actor mContainers[NUM_MESHES];
424 //Acts as a global light source, which can be dragged around.
425 Control mLightSource;
427 //Used to detect panning to rotate the selected model.
429 Vector2 mRotationStart;
431 int mModelIndex; //Index of model to load.
432 int mShaderIndex; //Index of shader type to use.
433 int mTag; //Identifies what kind of actor has been selected in OnTouch.
434 int mSelectedModelIndex; //Index of model selected on screen.
435 bool mPaused; //If true, all animations are paused and should stay so.
438 void RunTest( Application& application )
440 MeshRendererController test( application );
442 application.MainLoop();
445 // Entry point for Linux & Tizen applications
447 int main( int argc, char **argv )
449 Application application = Application::New( &argc, &argv );
451 RunTest( application );