[dali_1.3.26] Merge branch 'devel/master'
[platform/core/uifw/dali-demo.git] / examples / bezier-curve / bezier-curve-example.cpp
1 /*
2  * Copyright (c) 2018 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 #include <dali/dali.h>
19 #include <dali-toolkit/dali-toolkit.h>
20 #include "shared/view.h"
21
22 #include <sstream>
23
24 using namespace Dali;
25 using namespace Dali::Toolkit;
26
27 namespace
28 {
29
30 const Vector4 GRID_BACKGROUND_COLOR(0.85f, 0.85f, 0.85f, 1.0f);
31 const Vector4 CONTROL_POINT1_COLOR(Color::MAGENTA);
32 const Vector4 CONTROL_POINT2_COLOR(0.0, 0.9, 0.9, 1.0);
33 const Vector3 CONTROL_POINT1_ORIGIN(-100,  200, 0);
34 const Vector3 CONTROL_POINT2_ORIGIN( 100, -200, 0);
35 const char* const CIRCLE1_IMAGE( DEMO_IMAGE_DIR "circle1.png" );
36 const char* const CIRCLE2_IMAGE( DEMO_IMAGE_DIR "circle2.png" );
37 const char* const ANIMATION_BACKGROUND( DEMO_IMAGE_DIR "slider-skin.9.png" );
38 const char* APPLICATION_TITLE("Bezier curve animation");
39 const float ANIM_LEFT_FACTOR(0.2f);
40 const float ANIM_RIGHT_FACTOR(0.8f);
41
42
43 const char* CURVE_VERTEX_SHADER = DALI_COMPOSE_SHADER
44   (
45     attribute mediump vec2 aPosition;
46     uniform mediump mat4 uMvpMatrix;
47     uniform vec3 uSize;
48     void main()
49     {
50       gl_Position = uMvpMatrix * vec4(aPosition*uSize.xy, 0.0, 1.0);
51     }
52    );
53
54 const char* CURVE_FRAGMENT_SHADER = DALI_COMPOSE_SHADER
55   (
56     uniform lowp vec4 uColor;
57     void main()
58     {
59       gl_FragColor = vec4(0.0,0.0,0.0,1.0);
60     }
61    );
62
63
64 inline float Clamp(float v, float min, float max)
65 {
66   if(v<min) return min;
67   if(v>max) return max;
68   return v;
69 }
70
71 struct HandlePositionConstraint
72 {
73   HandlePositionConstraint( float minRelX, float maxRelX, float minRelY, float maxRelY )
74   : minRelX(minRelX), maxRelX(maxRelX), minRelY(minRelY), maxRelY(maxRelY)
75   {
76   }
77
78   void operator()( Vector3& current, const PropertyInputContainer& inputs )
79   {
80     Vector3 size( inputs[0]->GetVector3() );
81     current.x = Clamp(current.x, minRelX*size.x, maxRelX*size.x );
82     current.y = Clamp(current.y, minRelY*size.y, maxRelY*size.y );
83   }
84
85   float minRelX;
86   float maxRelX;
87   float minRelY;
88   float maxRelY;
89 };
90
91 void AnimatingPositionConstraint( Vector3& current, const PropertyInputContainer& inputs )
92 {
93   float positionFactor( inputs[0]->GetFloat() ); // -1 - 2
94   Vector3 size( inputs[1]->GetVector3() );
95
96   current.x = size.x * (positionFactor-0.5f); // size * (-1.5 - 1.5)
97 }
98
99 } //unnamed namespace
100
101
102
103 class BezierCurveExample : public ConnectionTracker
104 {
105 public:
106
107   BezierCurveExample( Application& application )
108   : mApplication( application ),
109     mControlPoint1(),
110     mControlPoint2(),
111     mControlLine1(),
112     mControlLine2(),
113     mAnimIcon1(),
114     mAnimIcon2(),
115     mDragActor(),
116     mCurve(),
117     mCoefficientLabel(),
118     mContentLayer(),
119     mGrid(),
120     mTimer(),
121     mDragAnimation(),
122     mBezierAnimation(),
123     mCurveVertices(),
124     mLine1Vertices(),
125     mLine2Vertices(),
126     mRelativeDragPoint(),
127     mLastControlPointPosition1(),
128     mLastControlPointPosition2(),
129     mPositionFactorIndex(),
130     mDuration( 2.0f ),
131     mControlPoint1Id( 0.0f ),
132     mControlPoint2Id( 0.0f ),
133     mControlPointScale( 0.5f ),
134     mControlPointZoomScale( mControlPointScale * 2.0 ),
135     mGoingRight( true )
136   {
137     // Connect to the Application's Init signal
138     mApplication.InitSignal().Connect( this, &BezierCurveExample::Create );
139   }
140
141   ~BezierCurveExample()
142   {
143     // Nothing to do here;
144   }
145
146   // The Init signal is received once (only) during the Application lifetime
147   void Create( Application& application )
148   {
149     // Hide the indicator bar
150     application.GetWindow().ShowIndicator( Dali::Window::INVISIBLE );
151
152     Stage stage = Stage::GetCurrent();
153     stage.KeyEventSignal().Connect( this, &BezierCurveExample::OnKeyEvent );
154
155     CreateBackground(stage);
156
157     mControlPointScale = 0.5f;
158     mControlPointZoomScale = mControlPointScale * 2.0f;
159
160     mContentLayer = Layer::New();
161     mContentLayer.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS );
162     mContentLayer.TouchSignal().Connect(this, &BezierCurveExample::OnTouchLayer);
163     mContentLayer.SetParentOrigin( ParentOrigin::CENTER );
164     stage.Add( mContentLayer );
165
166     // 6 rows: title, grid, coords, play, anim1, anim2
167     TableView contentLayout = TableView::New(5, 1);
168     contentLayout.SetName("contentLayout");
169     contentLayout.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS );
170     contentLayout.SetCellPadding( Size( 30, 30 ) );
171     contentLayout.SetParentOrigin(ParentOrigin::TOP_CENTER);
172     contentLayout.SetAnchorPoint(AnchorPoint::TOP_CENTER);
173     mContentLayer.Add( contentLayout );
174
175     // Create a TextLabel for the application title.
176     Toolkit::TextLabel label = Toolkit::TextLabel::New( APPLICATION_TITLE );
177     label.SetProperty( Toolkit::TextLabel::Property::HORIZONTAL_ALIGNMENT, "CENTER" );
178     label.SetProperty( Toolkit::TextLabel::Property::VERTICAL_ALIGNMENT, "CENTER" );
179     label.SetProperty( Toolkit::TextLabel::Property::TEXT_COLOR, Color::BLACK );
180     contentLayout.Add( label );
181     contentLayout.SetFitHeight(0);
182
183     mGrid = Control::New();
184
185     mGrid.SetResizePolicy( ResizePolicy::SIZE_RELATIVE_TO_PARENT, Dimension::WIDTH );
186     mGrid.SetResizePolicy( ResizePolicy::DIMENSION_DEPENDENCY, Dimension::HEIGHT );
187
188     mGrid.SetParentOrigin(ParentOrigin::CENTER);
189     mGrid.SetAnchorPoint(AnchorPoint::CENTER);
190     mGrid.SetBackgroundColor(GRID_BACKGROUND_COLOR);
191
192     contentLayout.Add( mGrid );
193     contentLayout.SetCellAlignment(1, HorizontalAlignment::CENTER, VerticalAlignment::CENTER );
194     CreateCubic(mGrid);
195     CreateControlPoints( mGrid ); // Control points constrained to double height of grid
196
197     mCoefficientLabel = TextLabel::New();
198     mCoefficientLabel.SetProperty( TextLabel::Property::ENABLE_MARKUP, true );
199     mCoefficientLabel.SetProperty( Toolkit::TextLabel::Property::HORIZONTAL_ALIGNMENT, "CENTER" );
200     mCoefficientLabel.SetProperty( Toolkit::TextLabel::Property::VERTICAL_ALIGNMENT, "CENTER" );
201     mCoefficientLabel.SetParentOrigin(ParentOrigin::CENTER);
202
203     contentLayout.Add( mCoefficientLabel );
204     SetLabel( Vector2(0,0), Vector2(1,1));
205     contentLayout.SetCellAlignment(2, HorizontalAlignment::CENTER, VerticalAlignment::CENTER );
206     contentLayout.SetFitHeight(2);
207
208     // Setup Play button and 2 icons to show off current anim and linear anim
209
210     PushButton play = PushButton::New();
211     play.SetName("Play");
212     play.SetParentOrigin(ParentOrigin::CENTER);
213     play.SetLabelText("Play");
214     play.ClickedSignal().Connect( this, &BezierCurveExample::OnPlayClicked );
215
216     contentLayout.Add( play );
217     contentLayout.SetCellAlignment(3, HorizontalAlignment::CENTER, VerticalAlignment::CENTER );
218     contentLayout.SetFitHeight(3);
219
220     auto animContainer = Control::New();
221     animContainer.SetName("AnimationContainer");
222     animContainer.SetParentOrigin( ParentOrigin::CENTER );
223     animContainer.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS );
224
225     auto animRail = Control::New();
226     animRail.SetProperty( Control::Property::BACKGROUND, Property::Map()
227                           .Add( Visual::Property::TYPE, Visual::IMAGE )
228                           .Add( ImageVisual::Property::URL, ANIMATION_BACKGROUND ) );
229     animRail.SetResizePolicy( ResizePolicy::SIZE_RELATIVE_TO_PARENT, Dimension::ALL_DIMENSIONS );
230     animRail.SetSizeModeFactor( Vector3( 0.666f, 0.2f, 1.0f ) );
231     animRail.SetParentOrigin( ParentOrigin::CENTER );
232     animContainer.Add( animRail );
233
234     contentLayout.Add( animContainer );
235     contentLayout.SetFixedHeight(4, 150 );
236
237     mAnimIcon1 = ImageView::New( CIRCLE1_IMAGE );
238     mAnimIcon1.SetParentOrigin( ParentOrigin::CENTER );
239     mAnimIcon1.SetAnchorPoint( AnchorPoint::CENTER );
240
241     // Would like some means of setting and animating position as a percentage of
242     // parent size without using constraints, but this will have to suffice for the moment.
243     mPositionFactorIndex = mAnimIcon1.RegisterProperty( "positionFactor", ANIM_LEFT_FACTOR); // range: 0-1 (+/- 1)
244     Constraint constraint = Constraint::New<Vector3>( mAnimIcon1, Actor::Property::POSITION, AnimatingPositionConstraint );
245     constraint.AddSource( Source( mAnimIcon1, mPositionFactorIndex ) );
246     constraint.AddSource( Source( animContainer, Actor::Property::SIZE ) );
247     constraint.Apply();
248
249     animContainer.Add( mAnimIcon1 );
250
251     // First UpdateCurve needs to run after size negotiation and after images have loaded
252     mGrid.OnRelayoutSignal().Connect( this, &BezierCurveExample::InitialUpdateCurve );
253
254     auto controlPoint1 = Control::DownCast( mControlPoint1 );
255     if( controlPoint1 )
256     {
257       controlPoint1.ResourceReadySignal().Connect( this, &BezierCurveExample::ControlPointReady );
258     }
259
260     auto controlPoint2 = Control::DownCast( mControlPoint2 );
261     if( controlPoint2 )
262     {
263       controlPoint2.ResourceReadySignal().Connect( this, &BezierCurveExample::ControlPointReady );
264     }
265   }
266
267   void ControlPointReady( Control control )
268   {
269     UpdateCurve();
270   }
271
272   void InitialUpdateCurve(Actor actor)
273   {
274     UpdateCurve();
275   }
276
277   void CreateBackground( Stage stage )
278   {
279     Toolkit::Control background = Dali::Toolkit::Control::New();
280     background.SetAnchorPoint( Dali::AnchorPoint::CENTER );
281     background.SetParentOrigin( Dali::ParentOrigin::CENTER );
282     background.SetResizePolicy( Dali::ResizePolicy::FILL_TO_PARENT, Dali::Dimension::ALL_DIMENSIONS );
283
284     Property::Map map;
285     map.Insert( Visual::Property::TYPE,  Visual::COLOR );
286     map.Insert( ColorVisual::Property::MIX_COLOR, Vector4( 253/255.0f, 245/255.0f, 230/255.0f, 1.0f ) );
287     background.SetProperty( Dali::Toolkit::Control::Property::BACKGROUND, map );
288     stage.Add( background );
289   }
290
291   void CreateCubic(Actor parent)
292   {
293     // Create a mesh to draw the cubic as a single line
294     mCurve = Actor::New();
295     mCurve.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS );
296     mCurve.SetParentOrigin( ParentOrigin::CENTER );
297
298     Shader shader = Shader::New( CURVE_VERTEX_SHADER, CURVE_FRAGMENT_SHADER );
299
300     Property::Map curveVertexFormat;
301     curveVertexFormat["aPosition"] = Property::VECTOR2;
302     mCurveVertices = PropertyBuffer::New( curveVertexFormat );
303     Vector2 vertexData[2] = { Vector2(-0.5f, 0.5f), Vector2( 0.5f, -0.5f ) };
304     mCurveVertices.SetData( vertexData, 2 );
305
306     Geometry geometry = Geometry::New();
307     geometry.AddVertexBuffer( mCurveVertices );
308     geometry.SetType( Geometry::LINE_STRIP );
309
310     Renderer renderer = Renderer::New( geometry, shader );
311     mCurve.AddRenderer( renderer );
312     parent.Add(mCurve);
313   }
314
315   Actor CreateControlPoint( Actor parent, const char* url, Vector3 position)
316   {
317     Actor actor = ImageView::New( url );
318     actor.SetScale( mControlPointScale);
319     actor.SetParentOrigin( ParentOrigin::CENTER );
320     // Curve and line drawing works off current value (i.e. last update frame's value). Need to animate to ensure
321     // initial position is baked to both frames before initially drawing the curve.
322     auto positionAnimation = Animation::New( 0.01f );
323     positionAnimation.AnimateTo( Property( actor, Actor::Property::POSITION ), position, AlphaFunction::EASE_IN_OUT );
324     positionAnimation.Play();
325     positionAnimation.FinishedSignal().Connect( this, &BezierCurveExample::OnAnimationFinished );
326
327     // Set up constraints for drag/drop
328     Constraint constraint = Constraint::New<Vector3>( actor, Actor::Property::POSITION, HandlePositionConstraint( -0.5, 0.5, -1, 1));
329     constraint.AddSource( Source( parent, Actor::Property::SIZE ) );
330     constraint.Apply();
331
332     actor.TouchSignal().Connect(this, &BezierCurveExample::OnTouchControlPoint);
333     return actor;
334   }
335
336   Actor CreateControlLine( PropertyBuffer vertexBuffer )
337   {
338     Actor line = Actor::New();
339     line.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS );
340     line.SetParentOrigin( ParentOrigin::CENTER );
341
342     Shader shader = Shader::New( CURVE_VERTEX_SHADER, CURVE_FRAGMENT_SHADER );
343     Geometry geometry = Geometry::New();
344     geometry.AddVertexBuffer( vertexBuffer );
345     geometry.SetType( Geometry::LINE_STRIP );
346
347     Renderer renderer = Renderer::New( geometry, shader );
348     line.AddRenderer( renderer );
349     return line;
350   }
351
352   void CreateControlPoints( Actor parent )
353   {
354     mControlPoint1 = CreateControlPoint( parent,
355                                          CIRCLE1_IMAGE,
356                                          CONTROL_POINT1_ORIGIN );
357     mControlPoint1Id = mControlPoint1.GetId();
358
359     mControlPoint2 = CreateControlPoint( parent,
360                                          CIRCLE2_IMAGE,
361                                          CONTROL_POINT2_ORIGIN );
362     mControlPoint2Id = mControlPoint2.GetId();
363
364     Property::Map lineVertexFormat;
365     lineVertexFormat["aPosition"] = Property::VECTOR2;
366     mLine1Vertices = PropertyBuffer::New( lineVertexFormat );
367     mLine2Vertices = PropertyBuffer::New( lineVertexFormat );
368
369     mControlLine1 = CreateControlLine( mLine1Vertices );
370     mControlLine2 = CreateControlLine( mLine2Vertices );
371
372     parent.Add( mControlLine1 );
373     parent.Add( mControlLine2 );
374     parent.Add( mControlPoint1 );
375     parent.Add( mControlPoint2 );
376   }
377
378   void SetLabel( Vector2 pos1, Vector2 pos2 )
379   {
380     std::ostringstream oss;
381     oss.setf(std::ios::fixed, std::ios::floatfield);
382     oss.precision(2);
383     oss << "( <color value='#971586'>" << pos1.x << ", " << pos1.y << ", </color>";
384     oss << "<color value='#e7640d'>" << pos2.x << ", " << pos2.y << "</color>";
385     oss << "<color value='black'> )</color>";
386
387     mCoefficientLabel.SetProperty( TextLabel::Property::TEXT, oss.str() );
388   }
389
390   Vector2 AlignToGrid( Vector3 actorPos, Vector3 gridSize )
391   {
392     actorPos /= gridSize; // => -0.5 - 0.5
393     actorPos.x = Clamp( actorPos.x, -0.5f, 0.5f );
394     return Vector2( actorPos.x + 0.5f, 0.5f - actorPos.y );
395   }
396
397   void GetControlPoints(Vector2& pt1, Vector2& pt2)
398   {
399     Vector3 gridSize = mGrid.GetProperty<Vector3>( Actor::Property::SIZE ); // Get target value
400
401     pt1 = AlignToGrid( mControlPoint1.GetCurrentPosition(), gridSize );
402     pt2 = AlignToGrid( mControlPoint2.GetCurrentPosition(), gridSize );
403   }
404
405   /**
406    * @param[in] actor The actor to get the position from
407    * @param[out] point The point in the grid in the range -0.5 -> 0.5 in x and y, with y up.
408    * @param[out] position The actor position, floored to the nearest pixel
409    */
410   void GetPoint( Actor actor, Vector2& point, Vector2& position)
411   {
412     auto gridSize = mGrid.GetProperty<Vector3>( Actor::Property::SIZE ); // Get target value
413     auto currentPosition = actor.GetCurrentPosition(); // Get constrained current value
414
415     position = Vector2( std::floor( currentPosition.x ), std::floor( currentPosition.y ) );
416
417     point.x = Clamp( position.x / gridSize.x, -0.5f, 0.5f ) + 0.5f;
418     point.y = 0.5f - position.y / gridSize.y;
419   }
420
421   void UpdateCurve()
422   {
423     Vector2 point1, point2;
424     Vector2 position1, position2;
425     const int NUMBER_OF_SEGMENTS(40);
426
427     GetPoint( mControlPoint1, point1, position1 );
428     GetPoint( mControlPoint2, point2, position2 );
429
430     if( position1 != mLastControlPointPosition1 ||
431         position2 != mLastControlPointPosition2 )
432     {
433       mLastControlPointPosition1 = position1;
434       mLastControlPointPosition2 = position2;
435
436       SetLabel( point1, point2 );
437
438       Path path = Path::New();
439       path.AddPoint(Vector3::ZERO);
440       path.AddPoint(Vector3(1.0f, 1.0f, 1.0f));
441       path.AddControlPoint( Vector3( point1.x, point1.y, 0 ) );
442       path.AddControlPoint( Vector3( point2.x, point2.y, 0 ) );
443
444       Dali::Vector<float> verts;
445
446       verts.Resize(2*(NUMBER_OF_SEGMENTS+1)); // 1 more point than segment
447       for( int i=0; i<=NUMBER_OF_SEGMENTS; ++i)
448       {
449         Vector3 position, tangent;
450         path.Sample( i/float(NUMBER_OF_SEGMENTS), position, tangent );
451         verts[i*2] = position.x-0.5;
452         verts[i*2+1] = 0.5-position.y;
453       }
454       mCurveVertices.SetData(&verts[0], NUMBER_OF_SEGMENTS+1);
455
456       Vector4 line1( -0.5f, 0.5f, point1.x-0.5f, 0.5f-point1.y );
457       mLine1Vertices.SetData( line1.AsFloat(), 2 );
458
459       Vector4 line2( 0.5f, -0.5f, point2.x-0.5f, 0.5f-point2.y );
460       mLine2Vertices.SetData( line2.AsFloat(), 2 );
461     }
462   }
463
464   bool OnTouchControlPoint( Actor controlPoint, const TouchData& event )
465   {
466     if( event.GetPointCount() > 0 )
467     {
468       if( event.GetState( 0 ) == PointState::DOWN )
469       {
470         Vector2 screenPoint = event.GetScreenPosition( 0 );
471         mRelativeDragPoint = screenPoint;
472         mRelativeDragPoint -= Vector2(controlPoint.GetCurrentPosition());
473         mDragActor = controlPoint;
474         mDragAnimation = Animation::New(0.25f);
475         mDragAnimation.AnimateTo( Property(mDragActor, Actor::Property::SCALE), Vector3( mControlPointZoomScale, mControlPointZoomScale, 1.0f), AlphaFunction::EASE_OUT);
476         mDragAnimation.Play();
477       }
478     }
479     return false; // Don't mark this as consumed - let the layer get the touch
480   }
481
482   bool OnTouchLayer( Actor actor, const TouchData& event )
483   {
484     if( event.GetPointCount() > 0 )
485     {
486       if( mDragActor )
487       {
488         Vector3 position( event.GetScreenPosition( 0 ) );
489
490         mDragActor.SetPosition( position - Vector3( mRelativeDragPoint ) );
491
492         if( event.GetState( 0 ) == PointState::UP ) // Stop dragging
493         {
494           mDragAnimation = Animation::New(0.25f);
495           mDragAnimation.AnimateTo( Property( mDragActor, Actor::Property::SCALE ), Vector3( mControlPointScale, mControlPointScale, 1.0f), AlphaFunction::EASE_IN);
496           mDragAnimation.FinishedSignal().Connect( this, &BezierCurveExample::OnAnimationFinished );
497           mDragAnimation.Play();
498           mDragActor.Reset();
499         }
500       }
501       UpdateCurve();
502     }
503     return false;
504   }
505
506   void OnAnimationFinished( Animation& animation )
507   {
508     UpdateCurve();
509   }
510
511   bool OnPlayClicked( Button button )
512   {
513     if( ! mBezierAnimation )
514     {
515       mBezierAnimation = Animation::New( mDuration );
516     }
517     mBezierAnimation.Stop();
518     mBezierAnimation.Clear();
519
520     float positionFactor = ANIM_LEFT_FACTOR;
521     if( mGoingRight )
522     {
523       positionFactor = ANIM_RIGHT_FACTOR;
524       mGoingRight = false;
525     }
526     else
527     {
528       mGoingRight = true;
529     }
530
531     Vector2 pt1, pt2;
532     GetControlPoints(pt1, pt2);
533
534     mBezierAnimation.AnimateTo( Property(mAnimIcon1, mPositionFactorIndex), positionFactor, AlphaFunction( pt1, pt2 ) );
535     mBezierAnimation.Play();
536     return true;
537   }
538
539   /**
540    * Main key event handler
541    */
542   void OnKeyEvent(const KeyEvent& event)
543   {
544
545     if( event.state == KeyEvent::Down && (IsKey( event, DALI_KEY_ESCAPE) || IsKey( event, DALI_KEY_BACK ))  )
546     {
547       mApplication.Quit();
548     }
549   }
550
551 private:
552   Application& mApplication;
553   Actor mControlPoint1;
554   Actor mControlPoint2;
555   Actor mControlLine1;
556   Actor mControlLine2;
557   ImageView mAnimIcon1;
558   ImageView mAnimIcon2;
559   Actor mDragActor;
560   Actor mCurve;
561   TextLabel mCoefficientLabel;
562   Layer mContentLayer;
563   Control mGrid;
564   Timer mTimer;
565   Animation mDragAnimation;
566   Animation mBezierAnimation;
567   PropertyBuffer mCurveVertices;
568   PropertyBuffer mLine1Vertices;
569   PropertyBuffer mLine2Vertices;
570   Vector2 mRelativeDragPoint;
571   Vector2 mLastControlPointPosition1;
572   Vector2 mLastControlPointPosition2;
573   Property::Index mPositionFactorIndex;
574   float mDuration;
575   unsigned int mControlPoint1Id;
576   unsigned int mControlPoint2Id;
577   float mControlPointScale;
578   float mControlPointZoomScale;
579   bool mGoingRight;
580 };
581
582
583 int main( int argc, char **argv )
584 {
585   Application application = Application::New( &argc, &argv );
586
587   BezierCurveExample test( application );
588   application.MainLoop();
589   return 0;
590 }