Added path animation demo
[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 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    * One-time setup in response to Application InitSignal.
61    */
62   void Create( Application& application )
63   {
64     // Get a handle to the stage:
65     Stage stage = Stage::GetCurrent();
66
67     // Connect to input event signals:
68     stage.KeyEventSignal().Connect(this, &PathController::OnKeyEvent);
69
70     // Create a default view with a default tool bar:
71     Toolkit::View view;                ///< The View instance.
72     Toolkit::ToolBar toolBar;          ///< The View's Toolbar.
73     mContentLayer = DemoHelper::CreateView( mApplication,
74                                             view,
75                                             toolBar,
76                                             BACKGROUND_IMAGE,
77                                             TOOLBAR_IMAGE,
78                                             "" );
79
80     mContentLayer.TouchedSignal().Connect(this, &PathController::OnTouchLayer);
81
82     //Title
83     TextView title = TextView::New();
84     toolBar.AddControl( title, DemoHelper::DEFAULT_VIEW_STYLE.mToolBarTitlePercentage, Alignment::HorizontalCenter );
85     Font font = Font::New();
86     title.SetText( APPLICATION_TITLE );
87     title.SetSize( font.MeasureText( APPLICATION_TITLE ) );
88     title.SetStyleToCurrentText(DemoHelper::GetDefaultTextStyle());
89
90     //Path
91     mPath = Dali::Path::New();
92     mPath.AddPoint( Vector3( 10.0f, stage.GetSize().y*0.5f, 0.0f ));
93     mPath.AddPoint( Vector3( stage.GetSize().x*0.5f, stage.GetSize().y*0.3f, 0.0f ));
94     mPath.GenerateControlPoints(0.25f);
95     DrawPath( 200u );
96
97     //Actor
98     ImageAttributes attributes;
99     Image img = ResourceImage::New(ACTOR_IMAGE, attributes );
100     mActor = ImageActor::New( img );
101     mActor.SetPosition( Vector3( 10.0f, stage.GetSize().y*0.5f, 0.0f ) );
102     mActor.SetAnchorPoint( AnchorPoint::CENTER );
103     mActor.SetSize( 100, 50, 1 );
104     stage.Add( mActor );
105
106     mForward = Vector3::XAXIS;
107     CreateAnimation();
108
109     Dali::TextActor forwardLabel = TextActor::New("Forward Vector");
110     forwardLabel.SetPosition( 10.0f, stage.GetSize().y - 60.0f, 0.0f );
111     forwardLabel.SetColor( Vector4(0.0f,0.0f,0.0f,1.0f));
112     forwardLabel.SetAnchorPoint( AnchorPoint::CENTER_LEFT);
113     mContentLayer.Add( forwardLabel );
114
115     //TextInput
116     Dali::Layer textInputLayer = Dali::Layer::New();
117     textInputLayer.SetSize( 400.0f, 30.0f, 0.0 );
118     textInputLayer.SetPosition( 0.0f, stage.GetSize().y - 30.0f, 0.0f );
119     textInputLayer.SetAnchorPoint( AnchorPoint::TOP_LEFT);
120     textInputLayer.SetParentOrigin( ParentOrigin::TOP_LEFT);
121     stage.Add( textInputLayer );
122     Dali::TextActor label = TextActor::New("X:");
123     label.SetPosition( 10.0f, 0.0f, 0.0f );
124     label.SetColor( Vector4(0.0f,0.0f,0.0f,1.0f));
125     label.SetAnchorPoint( AnchorPoint::CENTER_LEFT);
126     textInputLayer.Add( label );
127     TextStyle style;
128     style.SetTextColor( Vector4( 0.0f, 0.0f ,0.0f, 1.0f ));
129     mTextInput[0] = TextInput::New();
130     mTextInput[0].SetInitialText("1.0");
131     mTextInput[0].SetColor( Vector4(0.0f,0.0f,0.0f,1.0f));
132     mTextInput[0].SetAnchorPoint( AnchorPoint::CENTER_LEFT);
133     mTextInput[0].SetParentOrigin( ParentOrigin::CENTER_RIGHT);
134     mTextInput[0].SetPosition( 10.0f, 0.0f, 0.0f );
135     mTextInput[0].SetSize( 70.0f, 0.0f, 0.0f );
136     mTextInput[0].SetTextAlignment(Alignment::HorizontalCenter );
137     mTextInput[0].SetMaxCharacterLength( 5 );
138     mTextInput[0].SetNumberOfLinesLimit(1);
139     mTextInput[0].ApplyStyleToAll( style );
140     mTextInput[0].SetProperty( mTextInput[0].GetPropertyIndex("cursor-color"), Vector4(0.0f,0.0f,0.0f,1.0f) );
141     mTextInput[0].SetBackgroundColor( Vector4(0.8f,1.0f,0.8f, 0.4f));
142     mTextInput[0].InputFinishedSignal().Connect(this, &PathController::OnTextInputEnd);
143     mTextInput[0].SetEditOnTouch();
144     label.Add( mTextInput[0]);
145     label = TextActor::New("Y:");
146     label.SetPosition( 160.0f,0.0f, 0.0f );
147     label.SetColor( Vector4(0.0f,0.0f,0.0f,1.0f));
148     label.SetAnchorPoint( AnchorPoint::CENTER_LEFT);
149     textInputLayer.Add( label );
150     mTextInput[1] = TextInput::New();
151     mTextInput[1].SetInitialText("0.0");
152     mTextInput[1].SetColor( Vector4(0.0f,0.0f,0.0f,1.0f));
153     mTextInput[1].SetAnchorPoint( AnchorPoint::CENTER_LEFT);
154     mTextInput[1].SetParentOrigin( ParentOrigin::CENTER_RIGHT);
155     mTextInput[1].SetPosition( 10.0f, 0.0f, 0.0f );
156     mTextInput[1].SetSize( 70.0f, 0.0f, 0.0f );
157     mTextInput[1].SetTextAlignment(Alignment::HorizontalCenter );
158     mTextInput[1].SetMaxCharacterLength( 5 );
159     mTextInput[1].SetNumberOfLinesLimit(1);
160     mTextInput[1].ApplyStyleToAll( style );
161     mTextInput[1].SetProperty( mTextInput[1].GetPropertyIndex("cursor-color"), Vector4(0.0f,0.0f,0.0f,1.0f) );
162     mTextInput[1].SetBackgroundColor( Vector4(0.8f,1.0f,0.8f, 0.4f));
163     mTextInput[1].InputFinishedSignal().Connect(this, &PathController::OnTextInputEnd);
164     label.Add( mTextInput[1]);
165     label = TextActor::New("Z:");
166     label.SetPosition( 310.0f, 0.0f, 0.0f );
167     label.SetColor( Vector4(0.0f,0.0f,0.0f,1.0f));
168     label.SetAnchorPoint( AnchorPoint::CENTER_LEFT);
169     textInputLayer.Add( label );
170     mTextInput[2] = TextInput::New();
171     mTextInput[2].SetInitialText("0.0");
172     mTextInput[2].SetColor( Vector4(0.0f,0.0f,0.0f,1.0f));
173     mTextInput[2].SetAnchorPoint( AnchorPoint::CENTER_LEFT);
174     mTextInput[2].SetParentOrigin( ParentOrigin::CENTER_RIGHT);
175     mTextInput[2].SetPosition( 10.0f, 0.0f, 0.0f );
176     mTextInput[2].SetSize( 70.0f, 0.0f, 0.0f );
177     mTextInput[2].SetTextAlignment(Alignment::HorizontalCenter );
178     mTextInput[2].SetMaxCharacterLength( 5 );
179     mTextInput[2].SetNumberOfLinesLimit(1);
180     mTextInput[2].ApplyStyleToAll( style );
181     mTextInput[2].SetProperty( mTextInput[2].GetPropertyIndex("cursor-color"), Vector4(0.0f,0.0f,0.0f,1.0f) );
182     mTextInput[2].SetBackgroundColor( Vector4(0.8f,1.0f,0.8f, 0.4f));
183     mTextInput[2].InputFinishedSignal().Connect(this, &PathController::OnTextInputEnd);
184     label.Add( mTextInput[2]);
185   }
186
187   /**
188    * Create an actor representing a control point of the curve
189    * @param[in] name Name of the actor
190    * @param[in] size Size of the containing actor
191    * @param[in] imageSize Size of the imageActor
192    * @param[in] color Color of the imageActor
193    */
194   Actor CreateControlPoint(const std::string& name, const Vector3& size, const Vector3& imageSize, const Vector4& color )
195   {
196     Actor actor = Actor::New();
197     actor.SetParentOrigin( ParentOrigin::TOP_LEFT);
198     actor.SetAnchorPoint( AnchorPoint::CENTER );
199     actor.SetSize( size );
200     actor.SetName( name );
201     actor.TouchedSignal().Connect(this, &PathController::OnTouchPoint);
202
203     ImageActor imageActor = Toolkit::CreateSolidColorActor(color);
204     imageActor.SetColor(Vector4(1.0f,0.0f,0.0f,1.0f));
205     imageActor.SetParentOrigin( ParentOrigin::CENTER);
206     imageActor.SetAnchorPoint( AnchorPoint::CENTER );
207     imageActor.SetSize( imageSize );
208     actor.Add(imageActor );
209
210     return actor;
211   }
212
213   /**
214    * Draws the path and the control points for the path
215    * @param[in] resolution Number of segments for the path.
216    */
217   void DrawPath( unsigned int resolution )
218   {
219     Stage stage = Dali::Stage::GetCurrent();
220
221     //Create path mesh actor
222     Dali::MeshData meshData = MeshFactory::NewPath( mPath, resolution );
223     Dali::Material material = Material::New("LineMaterial");
224     material.SetDiffuseColor( Vector4(0.0f,0.0f,0.0f,1.0f));
225     meshData.SetMaterial(material);
226     Dali::Mesh mesh = Dali::Mesh::New( meshData );
227     if( mMeshPath )
228     {
229       stage.Remove( mMeshPath );
230     }
231     mMeshPath = Dali::MeshActor::New( mesh );
232     mMeshPath.SetAnchorPoint( AnchorPoint::TOP_LEFT );
233     mMeshPath.SetParentOrigin( ParentOrigin::TOP_LEFT );
234     stage.Add( mMeshPath );
235
236
237     ////Create mesh connecting interpolation points and control points
238     std::vector<Dali::MeshData::Vertex> vVertex;
239     std::vector<unsigned short> vIndex;
240     size_t pointCount = mPath.GetPointCount();
241     size_t controlPointIndex = 0;
242     for( size_t i(0); i<pointCount; ++i )
243     {
244       vVertex.push_back( MeshData::Vertex(mPath.GetPoint(i),Vector2::ZERO, Vector3::ZERO ) );
245       if( i<pointCount-1)
246       {
247         vVertex.push_back( MeshData::Vertex(mPath.GetControlPoint(controlPointIndex),Vector2::ZERO, Vector3::ZERO ));
248         vVertex.push_back( MeshData::Vertex(mPath.GetControlPoint(controlPointIndex+1),Vector2::ZERO, Vector3::ZERO ));
249       }
250       controlPointIndex += 2;
251     }
252
253     size_t segmentCount = 2*(pointCount-2)+2;
254     unsigned short index=0;
255     for( size_t i(0); i<segmentCount; ++i, ++index )
256     {
257       vIndex.push_back(index);
258       vIndex.push_back(index+1);
259
260       if( ~i & 1 )
261       {
262         index++;
263       }
264     }
265
266     meshData.SetLineData( vVertex, vIndex, material );
267     meshData.SetMaterial(material);
268     mesh = Dali::Mesh::New( meshData );
269     if( mMeshHandlers )
270     {
271       stage.Remove( mMeshHandlers );
272     }
273     mMeshHandlers = Dali::MeshActor::New( mesh );
274     mMeshHandlers.SetAnchorPoint( AnchorPoint::TOP_LEFT );
275     mMeshHandlers.SetParentOrigin( ParentOrigin::TOP_LEFT );
276     stage.Add( mMeshHandlers );
277
278
279     //Create actors representing interpolation points
280     for( size_t i(0); i<pointCount; ++i )
281     {
282       if( !mKnot[i] )
283       {
284         std::string name( "Knot");
285         name.push_back(i);
286         mKnot[i] = CreateControlPoint( name, Vector3(150.0f,150.0f,0.0f), Vector3(20.0f,20.0f,0.0f), Vector4(0.0f,0.0f,0.0f,1.0f) );
287         mContentLayer.Add(mKnot[i] );
288       }
289
290       mKnot[i].SetPosition( mPath.GetPoint(i) );
291     }
292
293     //Create actors representing control points
294     size_t controlPointCount=2*(pointCount-1);
295     for( size_t i(0); i<controlPointCount; ++i )
296     {
297       if( !mControlPoint[i])
298       {
299         std::string name( "ControlPoint");
300         name.push_back(i);
301         mControlPoint[i] = CreateControlPoint( name, Vector3(150.0f,150.0f,0.0f), Vector3(20.0f,20.0f,0.0f), Vector4(1.0f,0.0f,0.0f,1.0f) );
302         mContentLayer.Add(mControlPoint[i] );
303       }
304
305       mControlPoint[i].SetPosition( mPath.GetControlPoint(i) );
306     }
307   }
308
309   bool OnTouchPoint(Actor actor, const TouchEvent& event)
310   {
311     if(event.GetPointCount()>0)
312     {
313       const TouchPoint& point = event.GetPoint(0);
314
315       if(point.state==TouchPoint::Down)
316       {
317         // Start dragging
318         mDragActor = actor;
319       }
320     }
321     return false;
322   }
323
324   bool OnTouchLayer(Actor actor, const TouchEvent& event)
325   {
326     if(event.GetPointCount()>0)
327     {
328       const TouchPoint& point = event.GetPoint(0);
329
330       if(point.state==TouchPoint::Up)
331       {
332         //Stop dragging
333         mDragActor.Reset();
334       }
335       else if(!mDragActor && point.state==TouchPoint::Down && mPath.GetPointCount()<10 )
336       {
337         // Add new point
338         const TouchPoint& point = event.GetPoint(0);
339         Vector3 newPoint = Vector3(point.screen.x, point.screen.y, 0.0f);
340
341         size_t pointCount = mPath.GetPointCount();
342         Vector3 lastPoint = mPath.GetPoint( pointCount-1);
343         mPath.AddPoint( newPoint );
344
345         Vector3 displacement = (newPoint-lastPoint)/8;
346
347         mPath.AddControlPoint( lastPoint + displacement );
348         mPath.AddControlPoint( newPoint - displacement);
349
350         DrawPath( 200u );
351         CreateAnimation();
352       }
353       else
354       {
355         if( mDragActor )
356         {
357           const TouchPoint& point = event.GetPoint(0);
358           Vector3 newPosition = Vector3(point.screen.x, point.screen.y, 0.0f);
359
360           std::string actorName(mDragActor.GetName());
361
362           if( actorName.compare(0, 4, "Knot") == 0)
363           {
364              int index = actorName[4];
365              mPath.GetPoint(index) = newPosition;
366           }
367           else
368           {
369             int index = actorName[12];
370             mPath.GetControlPoint(index) = newPosition;
371           }
372
373           DrawPath( 200u );
374           CreateAnimation();
375         }
376       }
377     }
378     return false;
379   }
380
381  /**
382   * Main key event handler.
383   * Quit on escape key.
384   */
385   void OnKeyEvent(const KeyEvent& event)
386   {
387     if( event.state == KeyEvent::Down )
388     {
389       if( IsKey( event, Dali::DALI_KEY_ESCAPE ) ||
390           IsKey( event, Dali::DALI_KEY_BACK ) )
391       {
392         mApplication.Quit();
393       }
394     }
395   }
396
397   /**
398    * Callback called when user end to input text in any of the TextInput
399    * @param[in] textInput The text input that has generated the signal
400    */
401   void OnTextInputEnd( TextInput textInput)
402   {
403     mForward.x = (float)atof( mTextInput[0].GetText().c_str() );
404     mForward.y = (float)atof( mTextInput[1].GetText().c_str() );
405     mForward.z = (float)atof( mTextInput[2].GetText().c_str() );
406     CreateAnimation();
407   }
408
409   /**
410    * Create the path animation.
411    */
412   void CreateAnimation()
413   {
414     if( !mAnimation )
415     {
416       mAnimation = Animation::New( 2.0f );
417     }
418     else
419     {
420       mAnimation.Pause();
421       mAnimation.Clear();
422       mActor.SetRotation( Quaternion() );
423     }
424
425     mAnimation.Animate( mActor, mPath, mForward );
426     mAnimation.SetLooping( true );
427     mAnimation.Play();
428   }
429
430 private:
431   Application&  mApplication;
432
433   Layer      mContentLayer;       ///< The content layer
434
435   Path       mPath;               ///< The path used in the animation
436   ImageActor mActor;              ///< Actor being animated
437   Vector3    mForward;            ///< Current forward vector
438   Animation  mAnimation;          ///< Path animation
439
440   MeshActor  mMeshPath;           ///< Mesh actor for the path
441   MeshActor  mMeshHandlers;       ///< Mesh actor for the segments connecting points and control points
442   Actor mKnot[10];           ///< ImageActors for the interpolation points
443   Actor mControlPoint[18];   ///< ImageActors for the control points
444
445   Actor      mDragActor;          ///< Reference to the actor currently being dragged
446   TextInput  mTextInput[3];       ///< Text input to specify forward vector of the path animation
447 };
448
449 void RunTest( Application& application )
450 {
451   PathController test( application );
452
453   application.MainLoop();
454 }
455
456 /** Entry point for Linux & Tizen applications */
457 int main( int argc, char **argv )
458 {
459   Application application = Application::New( &argc, &argv );
460
461   RunTest( application );
462
463   return 0;
464 }