Merge "Readme file with wrong repo name" into tizen
[platform/core/uifw/dali-demo.git] / examples / path-animation / path-animation.cpp
1 /*
2  * Copyright (c) 2014 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 /**
19  * This example shows how to use path animations in DALi
20  */
21
22 // EXTERNAL INCLUDES
23 #include <dali-toolkit/dali-toolkit.h>
24
25 // INTERNAL INCLUDES
26 #include "shared/view.h"
27
28 using namespace Dali;
29 using namespace Dali::Toolkit;
30
31
32 namespace
33 {
34 const char* BACKGROUND_IMAGE( DALI_IMAGE_DIR "background-default.png" );
35 const char* ACTOR_IMAGE( DALI_IMAGE_DIR "dali-logo.png" );
36 const char* TOOLBAR_IMAGE( DALI_IMAGE_DIR "top-bar.png" );
37 const char* APPLICATION_TITLE( "Path Animation Example" );
38 }; //Unnamed namespace
39
40 /**
41  * @brief The main class of the demo.
42  */
43 class PathController : public ConnectionTracker
44 {
45 public:
46
47   PathController( Application& application )
48 : mApplication( application )
49 {
50     // Connect to the Application's Init signal
51     mApplication.InitSignal().Connect( this, &PathController::Create );
52 }
53
54   ~PathController()
55   {
56     // Nothing to do here.
57   }
58
59   /*
60    * Create a control composed of a label and an slider
61    * @param[in] label The text to be displayed ny the label
62    * @param[in] size The size of the slider
63    * @param[in] callback Pointer to the callback function to be called when user moves the slider
64   */
65   Actor CreateVectorComponentControl( const std::string& label, const Vector3& size, bool(PathController::*callback)(Slider,float) )
66   {
67     Dali::TextActor textActor = TextActor::New(label);
68     textActor.SetColor( Vector4(0.0f,0.0f,0.0f,1.0f));
69     textActor.SetSize(size.y,size.y,0.0f);
70
71     Slider slider = Slider::New();
72     slider.SetAnchorPoint( AnchorPoint::CENTER_LEFT);
73     slider.SetParentOrigin( ParentOrigin::CENTER_RIGHT);
74     slider.SetProperty(Slider::LOWER_BOUND_PROPERTY, -1.0f );
75     slider.SetProperty(Slider::UPPER_BOUND_PROPERTY, 1.0f );
76
77     Property::Array marks;
78     float mark = -1.0f;
79     for(unsigned short i(0); i<21; ++i )
80     {
81       marks.push_back( mark );
82       mark += 0.1f;
83     }
84
85     slider.SetProperty(Slider::MARKS_PROPERTY, marks);
86     slider.SetProperty(Slider::SNAP_TO_MARKS_PROPERTY, true );
87     slider.SetSize(size);
88     slider.SetScale( 0.5f );
89     slider.ValueChangedSignal().Connect(this,callback);
90     textActor.Add( slider );
91     return textActor;
92   }
93
94   /**
95    * Crate all the GUI controls
96    */
97   void CreateControls()
98   {
99     Stage stage = Stage::GetCurrent();
100
101     //TextInput
102     Dali::Layer controlsLayer = Dali::Layer::New();
103     controlsLayer.SetSize( stage.GetSize().x, stage.GetSize().y*0.3f, 0.0 );
104     controlsLayer.SetPosition( 0.0f, stage.GetSize().y*0.8f, 0.0f );
105     controlsLayer.SetAnchorPoint( AnchorPoint::TOP_LEFT);
106     controlsLayer.SetParentOrigin( ParentOrigin::TOP_LEFT);
107     controlsLayer.TouchedSignal().Connect(this, &PathController::OnTouchGuiLayer);
108     stage.Add( controlsLayer );
109
110     Vector3 textInputSize( stage.GetSize().x, stage.GetSize().y*0.04f, 0.0f );
111     Actor control0 = CreateVectorComponentControl("x:", textInputSize, &PathController::OnSliderXValueChange );
112     control0.SetY( stage.GetSize().y*0.05f );
113     control0.SetAnchorPoint(AnchorPoint::TOP_LEFT);
114     controlsLayer.Add( control0 );
115
116     Actor control1 = CreateVectorComponentControl("y:", textInputSize, &PathController::OnSliderYValueChange );
117     control1.SetAnchorPoint(AnchorPoint::TOP_LEFT);
118     control1.SetParentOrigin( ParentOrigin::BOTTOM_LEFT );
119     control1.SetPosition(0.0f,stage.GetSize().y*0.01,0.0f);
120     control0.Add( control1 );
121
122     Actor control2 =CreateVectorComponentControl("z:", textInputSize, &PathController::OnSliderZValueChange );
123     control2.SetAnchorPoint(AnchorPoint::TOP_LEFT);
124     control2.SetParentOrigin( ParentOrigin::BOTTOM_LEFT );
125     control2.SetPosition(0.0f,stage.GetSize().y*0.01,0.0f);
126     control1.Add( control2 );
127   }
128
129   /**
130    * Draws the path and the control points for the path
131    * @param[in] resolution Number of segments for the path.
132    */
133   void DrawPath( unsigned int resolution )
134   {
135     Stage stage = Dali::Stage::GetCurrent();
136
137     //Create path mesh actor
138     Dali::MeshData meshData = MeshFactory::NewPath( mPath, resolution );
139     Dali::Material material = Material::New("LineMaterial");
140     material.SetDiffuseColor( Vector4(0.0f,0.0f,0.0f,1.0f));
141     meshData.SetMaterial(material);
142     Dali::Mesh mesh = Dali::Mesh::New( meshData );
143     if( mMeshPath )
144     {
145       stage.Remove( mMeshPath );
146     }
147     mMeshPath = Dali::MeshActor::New( mesh );
148     mMeshPath.SetAnchorPoint( AnchorPoint::TOP_LEFT );
149     mMeshPath.SetParentOrigin( ParentOrigin::TOP_LEFT );
150     stage.Add( mMeshPath );
151
152
153     ////Create mesh connecting interpolation points and control points
154     std::vector<Dali::MeshData::Vertex> vVertex;
155     std::vector<unsigned short> vIndex;
156     size_t pointCount = mPath.GetPointCount();
157     size_t controlPointIndex = 0;
158     for( size_t i(0); i<pointCount; ++i )
159     {
160       vVertex.push_back( MeshData::Vertex(mPath.GetPoint(i),Vector2::ZERO, Vector3::ZERO ) );
161       if( i<pointCount-1)
162       {
163         vVertex.push_back( MeshData::Vertex(mPath.GetControlPoint(controlPointIndex),Vector2::ZERO, Vector3::ZERO ));
164         vVertex.push_back( MeshData::Vertex(mPath.GetControlPoint(controlPointIndex+1),Vector2::ZERO, Vector3::ZERO ));
165       }
166       controlPointIndex += 2;
167     }
168
169     size_t segmentCount = 2*(pointCount-2)+2;
170     unsigned short index=0;
171     for( size_t i(0); i<segmentCount; ++i, ++index )
172     {
173       vIndex.push_back(index);
174       vIndex.push_back(index+1);
175
176       if( ~i & 1 )
177       {
178         index++;
179       }
180     }
181
182     meshData.SetLineData( vVertex, vIndex, material );
183     meshData.SetMaterial(material);
184     mesh = Dali::Mesh::New( meshData );
185     if( mMeshHandlers )
186     {
187       stage.Remove( mMeshHandlers );
188     }
189     mMeshHandlers = Dali::MeshActor::New( mesh );
190     mMeshHandlers.SetAnchorPoint( AnchorPoint::TOP_LEFT );
191     mMeshHandlers.SetParentOrigin( ParentOrigin::TOP_LEFT );
192     stage.Add( mMeshHandlers );
193
194
195     //Create actors representing interpolation points
196     index = 0;
197     for( size_t i(0); i<pointCount; ++i )
198     {
199       if( !mControlPoint[index] )
200       {
201         mControlPoint[index] = Toolkit::CreateSolidColorActor(Vector4(1.0f,1.0f,1.0f,1.0f));
202         mControlPoint[index].SetParentOrigin( ParentOrigin::TOP_LEFT);
203         mControlPoint[index].SetAnchorPoint( AnchorPoint::CENTER );
204         mControlPoint[index].SetSize( 20.0f, 20.0f );
205         mContentLayer.Add(mControlPoint[index]);
206       }
207
208       std::string name( "Knot");
209       name.push_back(i);
210       mControlPoint[index].SetName( name );
211       mControlPoint[index].SetPosition( mPath.GetPoint(i) );
212       mControlPoint[index].SetColor( Vector4(0.0f,0.0f,0.0f,1.0f));
213       ++index;
214     }
215
216     //Create actors representing control points
217     size_t controlPointCount=2*(pointCount-1);
218     for( size_t i(0); i<controlPointCount; ++i )
219     {
220       if( !mControlPoint[index])
221       {
222         mControlPoint[index] = Toolkit::CreateSolidColorActor(Vector4(1.0f,1.0f,1.0f,1.0f));
223         mControlPoint[index].SetParentOrigin( ParentOrigin::TOP_LEFT);
224         mControlPoint[index].SetAnchorPoint( AnchorPoint::CENTER );
225         mControlPoint[index].SetSize( 20.0f, 20.0f );
226         mContentLayer.Add(mControlPoint[index]);
227       }
228       std::string name( "ControlPoint");
229       name.push_back(i);
230       mControlPoint[index].SetName( name );
231       mControlPoint[index].SetPosition( mPath.GetControlPoint(i) );
232       mControlPoint[index].SetColor( Vector4(1.0f,0.0f,0.0f,1.0f));
233       ++index;
234     }
235   }
236
237   /**
238    * Create the path animation.
239    */
240   void CreateAnimation()
241   {
242     if( !mAnimation )
243     {
244       mAnimation = Animation::New( 2.0f );
245     }
246     else
247     {
248       mAnimation.Pause();
249       mAnimation.Clear();
250       mActor.SetRotation( Quaternion() );
251     }
252
253     mAnimation.Animate( mActor, mPath, mForward );
254     mAnimation.SetLooping( true );
255     mAnimation.Play();
256   }
257
258   /**
259    * Get closest control point.void
260    * @param[in] point Point from where the distance is computed
261    * @return The closest actor if the distance is beyond 0.5cm or an uninitialized actor otherwise
262    */
263   Actor GetClosestActor(const Vector3& point)
264   {
265     size_t pointCount = mPath.GetPointCount();
266     size_t controlPointCount = 3*pointCount - 2;
267     Actor result;
268     float minDistance = 1.0/0.0;
269
270     for( size_t i(0); i<controlPointCount; ++i )
271     {
272       Vector3 v = mControlPoint[i].GetCurrentPosition() - point;
273       float distance = v.LengthSquared();
274       if( distance < minDistance )
275       {
276         result = mControlPoint[i];
277         minDistance = distance;
278       }
279     }
280
281     Vector2 dpi = Dali::Stage::GetCurrent().GetDpi();
282     float distanceTreshold = 0.2f * dpi.x * 0.2f * dpi.x;
283
284     if( minDistance < distanceTreshold )
285     {
286       return result;
287     }
288     else
289     {
290       return Actor();
291     }
292   }
293
294   /**
295    * Callback called when the background layer is touched
296    */
297   bool OnTouchLayer(Actor actor, const TouchEvent& event)
298   {
299     if(event.GetPointCount()>0)
300     {
301       const TouchPoint& point = event.GetPoint(0);
302
303       if(point.state==TouchPoint::Up)
304       {
305         //Stop dragging
306         mDragActor.Reset();
307       }
308       else if(point.state==TouchPoint::Down)
309       {
310         Vector3 touchPoint = Vector3(event.GetPoint(0).screen.x, event.GetPoint(0).screen.y, 0.0f);
311         if(!mDragActor )
312         {
313           mDragActor = GetClosestActor( touchPoint );
314           if( !mDragActor && mPath.GetPointCount() < 10 )
315           {
316             // Add new point
317             Vector3 lastPoint = mPath.GetPoint( mPath.GetPointCount()-1);
318             mPath.AddPoint( touchPoint );
319             Vector3 displacement = (touchPoint-lastPoint)/8;
320             mPath.AddControlPoint( lastPoint + displacement );
321             mPath.AddControlPoint( touchPoint - displacement);
322
323             DrawPath( 200u );
324             CreateAnimation();
325           }
326         }
327       }
328       else if( mDragActor && point.state==TouchPoint::Motion  )
329       {
330         Vector3 touchPoint = Vector3(event.GetPoint(0).screen.x, event.GetPoint(0).screen.y, 0.0f);
331         std::string actorName(mDragActor.GetName());
332         if( actorName.compare(0, 4, "Knot") == 0)
333         {
334           int index = actorName[4];
335           mPath.GetPoint(index) = touchPoint;
336         }
337         else
338         {
339           int index = actorName[12];
340           mPath.GetControlPoint(index) = touchPoint;
341         }
342
343         DrawPath( 200u );
344         CreateAnimation();
345       }
346     }
347
348     return true;
349   }
350
351   bool OnTouchGuiLayer(Actor actor, const TouchEvent& event)
352  {
353     mDragActor.Reset();
354     return false;
355  }
356   /**
357    * Callback called when user changes slider X
358    * @param[in] slider The slider that has generated the signal
359    * @param[in] value The new value
360    */
361   bool OnSliderXValueChange( Slider s, float value)
362   {
363     if( fabs( value ) - Math::MACHINE_EPSILON_1000 < 0.0f )
364     {
365       mForward.x = 0.0f;
366     }
367     else
368     {
369       mForward.x = value;
370     }
371
372     CreateAnimation();
373     return true;
374   }
375
376   /**
377    * Callback called when user changes slider Y
378    * @param[in] slider The slider that has generated the signal
379    * @param[in] value The new value
380    */
381   bool OnSliderYValueChange( Slider s, float value)
382   {
383     if( fabs( value ) - Math::MACHINE_EPSILON_1000 < 0.0f )
384     {
385       mForward.y = 0.0f;
386     }
387     else
388     {
389       mForward.y = value;
390     }
391     CreateAnimation();
392     return true;
393   }
394
395   /**
396    * Callback called when user changes slider Z
397    * @param[in] slider The slider that has generated the signal
398    * @param[in] value The new value
399    */
400   bool OnSliderZValueChange( Slider s, float value)
401   {
402     if( fabs( value ) - Math::MACHINE_EPSILON_1000 < 0.0f )
403     {
404       mForward.z = 0.0f;
405     }
406     else
407     {
408       mForward.z = value;
409     }
410
411     CreateAnimation();
412     return true;
413   }
414
415   /**
416    * Main key event handler.
417    * Quit on escape key.
418    */
419   void OnKeyEvent(const KeyEvent& event)
420   {
421     if( event.state == KeyEvent::Down )
422     {
423       if( IsKey( event, Dali::DALI_KEY_ESCAPE ) ||
424           IsKey( event, Dali::DALI_KEY_BACK ) )
425       {
426         mApplication.Quit();
427       }
428     }
429   }
430
431   /**
432    * One-time setup in response to Application InitSignal.
433    */
434   void Create( Application& application )
435   {
436     // Get a handle to the stage:
437     Stage stage = Stage::GetCurrent();
438
439     // Connect to input event signals:
440     stage.KeyEventSignal().Connect(this, &PathController::OnKeyEvent);
441
442     // Create a default view with a default tool bar:
443     Toolkit::View view;                ///< The View instance.
444     Toolkit::ToolBar toolBar;          ///< The View's Toolbar.
445     mContentLayer = DemoHelper::CreateView( mApplication,
446                                             view,
447                                             toolBar,
448                                             BACKGROUND_IMAGE,
449                                             TOOLBAR_IMAGE,
450                                             "" );
451
452     mContentLayer.TouchedSignal().Connect(this, &PathController::OnTouchLayer);
453
454     //Title
455     TextView title = TextView::New();
456     toolBar.AddControl( title, DemoHelper::DEFAULT_VIEW_STYLE.mToolBarTitlePercentage, Alignment::HorizontalCenter );
457     Font font = Font::New();
458     title.SetText( APPLICATION_TITLE );
459     title.SetSize( font.MeasureText( APPLICATION_TITLE ) );
460     title.SetStyleToCurrentText(DemoHelper::GetDefaultTextStyle());
461
462     //Path
463     mPath = Dali::Path::New();
464     mPath.AddPoint( Vector3( 10.0f, stage.GetSize().y*0.5f, 0.0f ));
465     mPath.AddPoint( Vector3( stage.GetSize().x*0.5f, stage.GetSize().y*0.5f, 0.0f ));
466     mPath.GenerateControlPoints(0.25f);
467     DrawPath( 200u );
468
469     //Actor
470     ImageAttributes attributes;
471     Image img = ResourceImage::New(ACTOR_IMAGE, attributes );
472     mActor = ImageActor::New( img );
473     mActor.SetAnchorPoint( AnchorPoint::CENTER );
474     mActor.SetSize( 100, 50, 1 );
475     stage.Add( mActor );
476
477     CreateAnimation();
478     CreateControls();
479   }
480
481 private:
482   Application&  mApplication;
483
484   Layer      mContentLayer;       ///< The content layer
485
486   Path       mPath;               ///< The path used in the animation
487   ImageActor mActor;              ///< Actor being animated
488   Vector3    mForward;            ///< Current forward vector
489   Animation  mAnimation;          ///< Path animation
490
491   MeshActor  mMeshPath;           ///< Mesh actor for the path
492   MeshActor  mMeshHandlers;       ///< Mesh actor for the handlers of the path
493
494   Actor      mControlPoint[28];   ///< ImageActors represeting control points of the path
495
496   Actor      mDragActor;          ///< Reference to the actor currently being dragged
497 };
498
499
500 void RunTest( Application& application )
501 {
502   PathController test( application );
503
504   application.MainLoop();
505 }
506
507 /** Entry point for Linux & Tizen applications */
508 int main( int argc, char **argv )
509 {
510   Application application = Application::New( &argc, &argv );
511
512   RunTest( application );
513
514   return 0;
515 }