Commit f3ed04afa90327dc193250db21d5a698ec4cca14
1 parent
fa6ffeff
Added support for setting light position in mesh renderer.
Change-Id: I1d0298c1e0cd30ac370bc27f45ffe0ade5d2d616
Showing
2 changed files
with
183 additions
and
47 deletions
demo/dali-demo.cpp
| ... | ... | @@ -42,7 +42,6 @@ int DALI_EXPORT_API main(int argc, char **argv) |
| 42 | 42 | demo.AddExample(Example("dissolve-effect.example", DALI_DEMO_STR_TITLE_DISSOLVE_TRANSITION)); |
| 43 | 43 | demo.AddExample(Example("item-view.example", DALI_DEMO_STR_TITLE_ITEM_VIEW)); |
| 44 | 44 | demo.AddExample(Example("magnifier.example", DALI_DEMO_STR_TITLE_MAGNIFIER)); |
| 45 | - demo.AddExample(Example("model3d-view.example", DALI_DEMO_STR_TITLE_MODEL_3D_VIEWER)); | |
| 46 | 45 | demo.AddExample(Example("motion-blur.example", DALI_DEMO_STR_TITLE_MOTION_BLUR)); |
| 47 | 46 | demo.AddExample(Example("motion-stretch.example", DALI_DEMO_STR_TITLE_MOTION_STRETCH)); |
| 48 | 47 | demo.AddExample(Example("page-turn-view.example", DALI_DEMO_STR_TITLE_PAGE_TURN_VIEW)); | ... | ... |
examples/mesh-renderer/mesh-renderer-example.cpp
| ... | ... | @@ -47,6 +47,11 @@ namespace |
| 47 | 47 | const float MODEL_SCALE = 0.75f; |
| 48 | 48 | const int NUM_MESHES = 3; |
| 49 | 49 | |
| 50 | + //Used to identify actors. | |
| 51 | + const int MODEL_TAG = 0; | |
| 52 | + const int LIGHT_TAG = 1; | |
| 53 | + const int LAYER_TAG = 2; | |
| 54 | + | |
| 50 | 55 | } //End namespace |
| 51 | 56 | |
| 52 | 57 | class MeshRendererController : public ConnectionTracker |
| ... | ... | @@ -57,7 +62,9 @@ public: |
| 57 | 62 | : mApplication( application ), //Store handle to the application. |
| 58 | 63 | mModelIndex( 1 ), //Start with metal robot. |
| 59 | 64 | mShaderIndex( 0 ), //Start with all textures. |
| 60 | - mSelectedModelIndex( 0 ) //Non-valid default, which will get set to a correct value when used. | |
| 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. | |
| 61 | 68 | { |
| 62 | 69 | // Connect to the Application's Init signal |
| 63 | 70 | mApplication.InitSignal().Connect( this, &MeshRendererController::Create ); |
| ... | ... | @@ -90,25 +97,24 @@ public: |
| 90 | 97 | { |
| 91 | 98 | Stage stage = Stage::GetCurrent(); |
| 92 | 99 | |
| 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 ); | |
| 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 ); | |
| 105 | 110 | |
| 106 | 111 | //Add containers to house each renderer-holding-actor. |
| 107 | 112 | for( int i = 0; i < NUM_MESHES; i++ ) |
| 108 | 113 | { |
| 109 | 114 | mContainers[i] = Actor::New(); |
| 110 | 115 | 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. | |
| 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. | |
| 112 | 118 | |
| 113 | 119 | //Position each container on screen |
| 114 | 120 | if( i == 0 ) |
| ... | ... | @@ -133,8 +139,8 @@ public: |
| 133 | 139 | mContainers[i].SetAnchorPoint( AnchorPoint::TOP_RIGHT ); |
| 134 | 140 | } |
| 135 | 141 | |
| 136 | - mPanGestureDetector.Attach( mContainers[i] ); | |
| 137 | - layer.Add( mContainers[i] ); | |
| 142 | + mContainers[i].TouchedSignal().Connect( this, &MeshRendererController::OnTouch ); | |
| 143 | + baseLayer.Add( mContainers[i] ); | |
| 138 | 144 | } |
| 139 | 145 | |
| 140 | 146 | //Set up models |
| ... | ... | @@ -169,19 +175,65 @@ public: |
| 169 | 175 | Toolkit::PushButton modelButton = Toolkit::PushButton::New(); |
| 170 | 176 | modelButton.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::ALL_DIMENSIONS ); |
| 171 | 177 | modelButton.ClickedSignal().Connect( this, &MeshRendererController::OnChangeModelClicked ); |
| 172 | - modelButton.SetParentOrigin( Vector3( 0.1, 0.95, 0.5 ) ); //Offset from bottom left | |
| 178 | + modelButton.SetParentOrigin( Vector3( 0.05, 0.95, 0.5 ) ); //Offset from bottom left | |
| 173 | 179 | modelButton.SetAnchorPoint( AnchorPoint::BOTTOM_LEFT ); |
| 174 | 180 | modelButton.SetLabelText( "Change Model" ); |
| 175 | - layer.Add( modelButton ); | |
| 181 | + baseLayer.Add( modelButton ); | |
| 176 | 182 | |
| 177 | 183 | //Create button for shader changing |
| 178 | 184 | Toolkit::PushButton shaderButton = Toolkit::PushButton::New(); |
| 179 | 185 | shaderButton.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::ALL_DIMENSIONS ); |
| 180 | 186 | shaderButton.ClickedSignal().Connect( this, &MeshRendererController::OnChangeShaderClicked ); |
| 181 | - shaderButton.SetParentOrigin( Vector3( 0.9, 0.95, 0.5 ) ); //Offset from bottom right | |
| 187 | + shaderButton.SetParentOrigin( Vector3( 0.95, 0.95, 0.5 ) ); //Offset from bottom right | |
| 182 | 188 | shaderButton.SetAnchorPoint( AnchorPoint::BOTTOM_RIGHT ); |
| 183 | 189 | shaderButton.SetLabelText( "Change Shader" ); |
| 184 | - layer.Add( shaderButton ); | |
| 190 | + baseLayer.Add( shaderButton ); | |
| 191 | + | |
| 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 ); | |
| 200 | + | |
| 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 ); | |
| 206 | + | |
| 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 ); | |
| 211 | + | |
| 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 ) ); | |
| 217 | + | |
| 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 ); | |
| 226 | + | |
| 227 | + //Connect to touch signal for dragging. | |
| 228 | + mLightSource.TouchedSignal().Connect( this, &MeshRendererController::OnTouch ); | |
| 229 | + | |
| 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 ); | |
| 234 | + | |
| 235 | + //Calling this sets the light position of each model to that of the light source control. | |
| 236 | + UpdateLight(); | |
| 185 | 237 | } |
| 186 | 238 | |
| 187 | 239 | //Updates the displayed models to account for parameter changes. |
| ... | ... | @@ -194,6 +246,7 @@ public: |
| 194 | 246 | map.Insert( "materialUrl", MATERIAL_FILE[mModelIndex] ); |
| 195 | 247 | map.Insert( "texturesPath", TEXTURES_PATH ); |
| 196 | 248 | map.Insert( "shaderType", SHADER_TYPE[mShaderIndex] ); |
| 249 | + map.Insert( "useSoftNormals", false ); | |
| 197 | 250 | |
| 198 | 251 | //Set the two controls to use the mesh |
| 199 | 252 | for( int i = 0; i < NUM_MESHES; i++ ) |
| ... | ... | @@ -202,53 +255,101 @@ public: |
| 202 | 255 | } |
| 203 | 256 | } |
| 204 | 257 | |
| 205 | - //Rotates the panned model based on the gesture. | |
| 206 | - void OnPan( Actor actor, const PanGesture& gesture ) | |
| 258 | + //Updates the light position for each model to account for changes in the source on screen. | |
| 259 | + void UpdateLight() | |
| 207 | 260 | { |
| 208 | - switch( gesture.state ) | |
| 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 ); | |
| 264 | + | |
| 265 | + for( int i = 0; i < NUM_MESHES; ++i ) | |
| 209 | 266 | { |
| 210 | - case Gesture::Started: | |
| 211 | - { | |
| 212 | - //Find out which model has been selected | |
| 213 | - actor.GetProperty( actor.GetPropertyIndex( "Tag" ) ).Get( mSelectedModelIndex ); | |
| 267 | + mModels[i].control.RegisterProperty( "lightPosition", lightPosition, Property::ANIMATABLE ); | |
| 268 | + } | |
| 269 | + } | |
| 214 | 270 | |
| 215 | - //Pause current animation, as the gesture will be used to manually rotate the model | |
| 216 | - mModels[mSelectedModelIndex].rotationAnimation.Pause(); | |
| 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 ) | |
| 274 | + { | |
| 275 | + //Get primary touch point. | |
| 276 | + const Dali::TouchPoint& point = event.GetPoint( 0 ); | |
| 217 | 277 | |
| 218 | - break; | |
| 219 | - } | |
| 220 | - case Gesture::Continuing: | |
| 278 | + switch( point.state ) | |
| 279 | + { | |
| 280 | + case TouchPoint::Down: | |
| 221 | 281 | { |
| 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); | |
| 282 | + //Determine what was touched. | |
| 283 | + actor.GetProperty( actor.GetPropertyIndex( "Tag" ) ).Get( mTag ); | |
| 284 | + | |
| 285 | + if( mTag == MODEL_TAG ) | |
| 286 | + { | |
| 287 | + //Find out which model has been selected | |
| 288 | + actor.GetProperty( actor.GetPropertyIndex( "Model" ) ).Get( mSelectedModelIndex ); | |
| 289 | + | |
| 290 | + //Pause current animation, as the touch gesture will be used to manually rotate the model | |
| 291 | + mModels[mSelectedModelIndex].rotationAnimation.Pause(); | |
| 227 | 292 | |
| 228 | - mModels[mSelectedModelIndex].control.SetOrientation( rotation ); | |
| 293 | + //Store start points. | |
| 294 | + mPanStart = point.screen; | |
| 295 | + mRotationStart = mModels[mSelectedModelIndex].rotation; | |
| 296 | + } | |
| 229 | 297 | |
| 230 | 298 | break; |
| 231 | 299 | } |
| 232 | - case Gesture::Finished: | |
| 300 | + case TouchPoint::Motion: | |
| 233 | 301 | { |
| 234 | - //Return to automatic animation | |
| 235 | - mModels[mSelectedModelIndex].rotationAnimation.Play(); | |
| 302 | + //Switch on the kind of actor we're interacting with. | |
| 303 | + switch( mTag ) | |
| 304 | + { | |
| 305 | + case MODEL_TAG: //Rotate model | |
| 306 | + { | |
| 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); | |
| 313 | + | |
| 314 | + //Apply rotation. | |
| 315 | + mModels[mSelectedModelIndex].control.SetOrientation( rotation ); | |
| 316 | + | |
| 317 | + break; | |
| 318 | + } | |
| 319 | + case LIGHT_TAG: //Drag light | |
| 320 | + { | |
| 321 | + //Set light source to new position and update the models accordingly. | |
| 322 | + mLightSource.SetPosition( Vector3( point.screen ) ); | |
| 323 | + UpdateLight(); | |
| 324 | + | |
| 325 | + break; | |
| 326 | + } | |
| 327 | + } | |
| 236 | 328 | |
| 237 | 329 | break; |
| 238 | 330 | } |
| 239 | - case Gesture::Cancelled: | |
| 331 | + case TouchPoint::Interrupted: //Same as finished. | |
| 332 | + case TouchPoint::Finished: | |
| 240 | 333 | { |
| 241 | - //Return to automatic animation | |
| 242 | - mModels[mSelectedModelIndex].rotationAnimation.Play(); | |
| 334 | + if( mTag == MODEL_TAG ) | |
| 335 | + { | |
| 336 | + //Return to automatic animation | |
| 337 | + if( !mPaused ) | |
| 338 | + { | |
| 339 | + mModels[mSelectedModelIndex].rotationAnimation.Play(); | |
| 340 | + } | |
| 341 | + } | |
| 243 | 342 | |
| 244 | 343 | break; |
| 245 | 344 | } |
| 246 | 345 | default: |
| 247 | 346 | { |
| 248 | - //We can ignore other gestures and gesture states. | |
| 347 | + //Other touch states do nothing. | |
| 249 | 348 | break; |
| 250 | 349 | } |
| 251 | 350 | } |
| 351 | + | |
| 352 | + return true; | |
| 252 | 353 | } |
| 253 | 354 | |
| 254 | 355 | //Cycle through the list of models. |
| ... | ... | @@ -271,6 +372,36 @@ public: |
| 271 | 372 | return true; |
| 272 | 373 | } |
| 273 | 374 | |
| 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 ) | |
| 378 | + { | |
| 379 | + //Toggle pause state. | |
| 380 | + mPaused = !mPaused; | |
| 381 | + | |
| 382 | + //If we wish to pause animations, do so and keep them paused. | |
| 383 | + if( mPaused ) | |
| 384 | + { | |
| 385 | + for( int i = 0; i < NUM_MESHES ; ++i ) | |
| 386 | + { | |
| 387 | + mModels[i].rotationAnimation.Pause(); | |
| 388 | + } | |
| 389 | + | |
| 390 | + button.SetLabelText( " > " ); | |
| 391 | + } | |
| 392 | + else //Unpause all animations again. | |
| 393 | + { | |
| 394 | + for( int i = 0; i < NUM_MESHES ; ++i ) | |
| 395 | + { | |
| 396 | + mModels[i].rotationAnimation.Play(); | |
| 397 | + } | |
| 398 | + | |
| 399 | + button.SetLabelText( " || " ); | |
| 400 | + } | |
| 401 | + | |
| 402 | + return true; | |
| 403 | + } | |
| 404 | + | |
| 274 | 405 | //If escape or the back button is pressed, quit the application (and return to the launcher) |
| 275 | 406 | void OnKeyEvent( const KeyEvent& event ) |
| 276 | 407 | { |
| ... | ... | @@ -290,12 +421,18 @@ private: |
| 290 | 421 | Model mModels[NUM_MESHES]; |
| 291 | 422 | Actor mContainers[NUM_MESHES]; |
| 292 | 423 | |
| 424 | + //Acts as a global light source, which can be dragged around. | |
| 425 | + Control mLightSource; | |
| 426 | + | |
| 293 | 427 | //Used to detect panning to rotate the selected model. |
| 294 | - PanGestureDetector mPanGestureDetector; | |
| 428 | + Vector2 mPanStart; | |
| 429 | + Vector2 mRotationStart; | |
| 295 | 430 | |
| 296 | 431 | int mModelIndex; //Index of model to load. |
| 297 | 432 | int mShaderIndex; //Index of shader type to use. |
| 433 | + int mTag; //Identifies what kind of actor has been selected in OnTouch. | |
| 298 | 434 | int mSelectedModelIndex; //Index of model selected on screen. |
| 435 | + bool mPaused; //If true, all animations are paused and should stay so. | |
| 299 | 436 | }; |
| 300 | 437 | |
| 301 | 438 | void RunTest( Application& application ) | ... | ... |