Commit f3ed04afa90327dc193250db21d5a698ec4cca14

Authored by Andrew Poor
1 parent fa6ffeff

Added support for setting light position in mesh renderer.

Change-Id: I1d0298c1e0cd30ac370bc27f45ffe0ade5d2d616
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 )
... ...