Use new TouchData API
[platform/core/uifw/dali-demo.git] / examples / metaball-explosion / metaball-explosion-example.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 //External includes
19 #include <cstdio>
20 #include <string>
21
22 //Internal includes
23 #include <dali/dali.h>
24 #include <dali/devel-api/rendering/renderer.h>
25 #include <dali-toolkit/dali-toolkit.h>
26
27 #include "shared/view.h"
28
29 using namespace Dali;
30 using namespace Dali::Toolkit;
31
32 namespace
33 {
34 const char * const BACKGROUND_IMAGE( DEMO_IMAGE_DIR "background-2.jpg" );
35 const char * const TOOLBAR_IMAGE( DEMO_IMAGE_DIR "top-bar.png" );
36
37 const float GRAVITY_X(0);
38 const float GRAVITY_Y(-0.09);
39 }
40
41 #define METABALL_NUMBER 6
42
43
44 const char*const METABALL_VERTEX_SHADER = DALI_COMPOSE_SHADER (
45     attribute mediump vec2    aPosition;\n
46     attribute mediump vec2    aTexture;\n
47     uniform   mediump mat4    uMvpMatrix;\n
48     uniform   mediump vec3    uSize;\n
49     uniform   lowp    vec4    uColor;\n
50     varying   mediump vec2    vTexCoord;\n
51
52     void main()\n
53     {\n
54       vTexCoord = aTexture;\n
55       mediump vec4 vertexPosition = vec4(aPosition.x, aPosition.y, 0.0, 1.0);\n
56       gl_Position = uMvpMatrix * vertexPosition;\n
57     }\n
58 );
59
60
61 const char*const METABALL_FRAG_SHADER = DALI_COMPOSE_SHADER (
62   precision mediump float;\n
63   varying vec2 vTexCoord;\n
64   uniform vec2 uPositionMetaball;\n
65   uniform vec2 uPositionVar;\n
66   uniform vec2 uGravityVector;\n
67   uniform float uRadius;\n
68   uniform float uRadiusVar;\n
69   void main()\n
70   {\n
71     vec2 adjustedCoords = vTexCoord * 2.0 - 1.0;\n
72     vec2 finalMetaballPosition = uPositionMetaball + uGravityVector + uPositionVar;\n
73     \n
74     float finalRadius = uRadius + uRadiusVar;\n
75     vec2 distanceVec = adjustedCoords - finalMetaballPosition;\n
76     float result = dot(distanceVec, distanceVec);\n
77     float color = inversesqrt(result) * finalRadius;\n
78     \n
79     gl_FragColor = vec4(color,color,color,1.0);\n
80   }\n
81 );
82
83 const char*const REFRACTION_FRAG_SHADER = DALI_COMPOSE_SHADER (
84   precision highp float;\n
85   varying vec2 vTexCoord;\n
86   uniform sampler2D sTexture;\n
87   uniform sampler2D sEffect;\n
88   uniform vec2 uPositionMetaball;\n
89   void main()\n
90   {\n
91     vec2 zoomCoords;\n
92     vec3 normal = vec3(0.0,0.0,1.0);\n
93     vec2 fakePos = vec2(0.0,0.0);\n
94     vec3 color = vec3(1.0, 1.0, 1.0);
95     float ambient = 0.2;
96     \n
97     vec4 metaColor = texture2D(sEffect, vTexCoord);\n
98     \n
99     vec2 adjustedCoords = vTexCoord.xy * vec2(2.0) - vec2(1.0);\n
100     fakePos = adjustedCoords.xy - vec2(uPositionMetaball.x, -uPositionMetaball.y);
101     float len = length(fakePos) + 0.01;\n
102     vec3 colorPos = vec3(0,0,1);
103     \n
104     if (metaColor.r > 0.85)\n
105     {\n
106       zoomCoords = ((vTexCoord - 0.5) * 0.9);\n
107       zoomCoords = zoomCoords + 0.5;\n
108       \n
109       float interpNormal = mix(0.7, 1.0, (metaColor.r - 0.85) * 4.);\n
110       normal.xyz = vec3(fakePos.x * (1.0 - interpNormal) / len, fakePos.y * (1.0 - interpNormal) / len, interpNormal);\n
111       normal.xyz = normalize(normal.xyz);\n
112       color = vec3(0.65, 1.0, 0);\n
113       colorPos = vec3(fakePos.x,fakePos.y,0);
114     }\n
115     else if (metaColor.r > 0.75)\n
116     {\n
117       float interpolation = mix(0.9, 1.15, (0.85 - metaColor.r) * 10.0);\n
118       zoomCoords = ((vTexCoord - 0.5) * interpolation);\n
119       zoomCoords = zoomCoords + 0.5;\n
120       \n
121       float interpNormal = mix(0.7, 0.0, (0.85 - metaColor.r) * 10.0);\n
122       normal.xyz = vec3(fakePos.x * (1.0 - interpNormal) / len, fakePos.y * (1.0 - interpNormal) / len, interpNormal);\n
123       normal.xyz = normalize(normal.xyz);\n
124       color = vec3(0.65, 1.0, 0);\n
125       colorPos = vec3(fakePos.x,fakePos.y,0);
126     }\n
127     else\n
128     {\n
129       zoomCoords = vTexCoord;\n
130       normal = vec3(0,0,0);\n
131       ambient = 0.5;\n
132     }\n
133     \n
134     vec3 lightPosition = vec3(-750.0,-1000.0,2000.0);\n
135     vec3 vertex = vec3(adjustedCoords.x,adjustedCoords.y,0.0);\n
136     \n
137     vec3 vecToLight = normalize( lightPosition - vertex );\n
138     \n
139     float lightDiffuse = dot( vecToLight, normal );\n
140     lightDiffuse = max(0.0,lightDiffuse);\n
141     lightDiffuse = lightDiffuse * 0.5 + 0.5;
142     \n
143     vec3 vertexToEye = vec3(0,0,1) - vertex;\n
144     vertexToEye = normalize(vertexToEye);
145     vec3 lightReflect = normalize(reflect(-vecToLight, normal));\n
146     float specularFactor = max(0.0,dot(vertexToEye, lightReflect));\n
147     specularFactor = pow(specularFactor, 32.0) * 0.7;
148     \n
149     vec4 texColor = texture2D(sTexture, zoomCoords);\n
150     gl_FragColor.rgb = texColor.rgb * ambient + color.rgb * texColor.rgb * lightDiffuse + vec3(specularFactor);\n
151     gl_FragColor.a = 1.0;
152   }\n
153  );
154
155 const char*const FRAG_SHADER = DALI_COMPOSE_SHADER (
156   precision mediump float;\n
157   void main()\n
158   {\n
159     gl_FragColor = texture2D(sTexture, vTexCoord);\n
160   }\n
161 );
162
163
164 struct MetaballInfo
165 {
166   Actor         actor;
167   Vector2       position;
168   float         radius;
169   float         initRadius;
170
171   //new shader stuff
172   Property::Index positionIndex;
173   Property::Index positionVarIndex;
174 };
175
176
177 /**************************************************************************/
178 /* Demo using Metaballs                                         ***********/
179 /* When the metaball is clicked it explodes in different balls  ***********/
180 /**************************************************************************/
181 class MetaballExplosionController : public ConnectionTracker
182 {
183 public:
184   MetaballExplosionController( Application& application );
185   ~MetaballExplosionController();
186
187   /**
188    * Main create function, it creates the metaballs and all the related data
189    */
190   void Create( Application& app );
191
192   /**
193    * Touch event function
194    */
195   bool OnTouch( Actor actor, const TouchData& touch );
196
197   /**
198    * Key event function
199    */
200   void OnKeyEvent(const KeyEvent& event);
201
202
203 private:
204   Application&      mApplication;
205   Vector2           mScreenSize;
206
207   Layer             mContentLayer;
208
209   Image             mBackImage;
210   FrameBufferImage  mMetaballFBO;
211
212   Actor             mMetaballRoot;
213   MetaballInfo      mMetaballs[METABALL_NUMBER];
214
215   Property::Index   mPositionIndex;
216   Actor             mCompositionActor;
217
218   //Motion
219   Vector2           mCurrentTouchPosition;
220   Vector2           mMetaballPosVariation;
221   Vector2           mMetaballPosVariationFrom;
222   Vector2           mMetaballPosVariationTo;
223   Vector2           mMetaballCenter;
224
225   //Animations
226   Animation         mPositionVarAnimation[METABALL_NUMBER];
227
228   int               mDispersion;
229   Animation         mDispersionAnimation[METABALL_NUMBER];
230
231   Timer             mTimerDispersion;
232
233   float             mTimeMult;
234
235   //Private functions
236
237   /**
238    * Create a mesh data with the geometry for the metaball rendering
239    */
240   Geometry          CreateGeometry();
241
242   /**
243    * Create a mesh data with the geometry for the final composition
244    */
245   Geometry          CreateGeometryComposition();
246
247   /**
248    * Create a mesh actor for the metaballs
249    */
250   void              CreateMetaballActors();
251
252   /**
253    * Create the render task and FBO to render the metaballs into a texture
254    */
255   void              CreateMetaballImage();
256
257   /**
258    * Create a mesh image to render the final composition
259    */
260   void              AddRefractionImage();
261
262   /**
263    * Function to create animations for the small variations of position inside the metaball
264    */
265   void              CreateAnimations();
266
267   /**
268    * Function to reset metaball state
269    */
270   void              ResetMetaballs(bool resetAnims);
271
272   /**
273    * Function to create disperse each of the ball that compose the metaball when exploding
274    */
275   void              DisperseBallAnimation(int ball);
276
277   /**
278    * Function to make metaballs come back to reset position
279    */
280   void              LaunchResetMetaballPosition(Animation &source);
281
282   /**
283    * Function to set things at the end of the animation
284    */
285   void              EndDisperseAnimation(Animation &source);
286
287   /**
288    * Function to init dispersion of the metaballs one by one using a timer
289    * (so not all the balls begin moving at the same time)
290    */
291   bool              OnTimerDispersionTick();
292
293   /**
294    * Function to set the actual position of the metaballs when the user clicks the screen
295    */
296   void              SetPositionToMetaballs(Vector2 & metaballCenter);
297 };
298
299
300 //-----------------------------------------------------------------------------------------------
301 //
302 //  IMPLEMENTATION
303 //
304 //----------------
305
306 MetaballExplosionController::MetaballExplosionController( Application& application )
307   : mApplication( application )
308 {
309   // Connect to the Application's Init signal
310   mApplication.InitSignal().Connect( this, &MetaballExplosionController::Create );
311 }
312
313 MetaballExplosionController::~MetaballExplosionController()
314 {
315   // Nothing to do here;
316 }
317
318 void MetaballExplosionController::Create( Application& app )
319 {
320   Stage stage = Stage::GetCurrent();
321
322   stage.KeyEventSignal().Connect(this, &MetaballExplosionController::OnKeyEvent);
323
324   mScreenSize = stage.GetSize();
325
326   mTimeMult = 1.0f;
327
328   stage.SetBackgroundColor(Color::BLACK);
329
330   //Set background image for the view
331   mBackImage = ResourceImage::New( BACKGROUND_IMAGE );
332
333   srand((unsigned)time(0));
334
335   //Create internal data
336   CreateMetaballActors();
337   CreateMetaballImage();
338   AddRefractionImage();
339
340   CreateAnimations();
341
342   mDispersion = 0;
343   mTimerDispersion = Timer::New( 150 );
344   mTimerDispersion.TickSignal().Connect(this, &MetaballExplosionController::OnTimerDispersionTick);
345
346   // Connect the callback to the touch signal on the mesh actor
347   stage.GetRootLayer().TouchSignal().Connect( this, &MetaballExplosionController::OnTouch );
348 }
349
350 Geometry MetaballExplosionController::CreateGeometry()
351 {
352   float aspect = (float)mScreenSize.y / (float)mScreenSize.x;
353
354   // Create vertices and specify their color
355   float xsize = mScreenSize.x * 0.5;
356
357   //We create the meshdata for the metaballs
358   struct VertexPosition { Vector2 position; };
359   struct VertexTexture { Vector2 texture; };
360   struct VertexNormal { Vector3 normal; };
361
362   VertexPosition vertices[] = {
363     { Vector2( -xsize, -xsize * aspect) },
364     { Vector2(  xsize, -xsize * aspect) },
365     { Vector2( -xsize,  xsize * aspect) },
366     { Vector2(  xsize,  xsize * aspect) }
367   };
368
369   VertexTexture textures[] = {
370     { Vector2(0.0f, 0.0f) },
371     { Vector2(1.0f, 0.0f) },
372     { Vector2(0.0f, 1.0f * aspect) },
373     { Vector2(1.0f, 1.0f * aspect) }
374   };
375
376   unsigned int numberOfVertices = sizeof(vertices)/sizeof(VertexPosition);
377
378   //Vertices
379   Property::Map positionVertexFormat;
380   positionVertexFormat["aPosition"] = Property::VECTOR2;
381   PropertyBuffer positionVertices = PropertyBuffer::New( positionVertexFormat );
382   positionVertices.SetData( vertices, numberOfVertices );
383
384   //Textures
385   Property::Map textureVertexFormat;
386   textureVertexFormat["aTexture"] = Property::VECTOR2;
387   PropertyBuffer textureVertices = PropertyBuffer::New( textureVertexFormat );
388   textureVertices.SetData( textures, numberOfVertices );
389
390   //Indices
391   unsigned short indices[] = { 0, 3, 1, 0, 2, 3 };
392
393   // Create the geometry object
394   Geometry texturedQuadGeometry = Geometry::New();
395   texturedQuadGeometry.AddVertexBuffer( positionVertices );
396   texturedQuadGeometry.AddVertexBuffer( textureVertices );
397
398   texturedQuadGeometry.SetIndexBuffer ( &indices[0], sizeof( indices )/ sizeof( indices[0] ) );
399
400   return texturedQuadGeometry;
401 }
402
403 Geometry MetaballExplosionController::CreateGeometryComposition()
404 {
405   float aspect = (float)mScreenSize.y / (float)mScreenSize.x;
406
407   // Create vertices and specify their color
408   float xsize = mScreenSize.x * 0.5;
409
410   //We create the meshdata for the metaballs
411   struct VertexPosition { Vector2 position; };
412   struct VertexTexture { Vector2 texture; };
413   struct VertexNormal { Vector3 normal; };
414
415   VertexPosition vertices[] = {
416     { Vector2( -xsize, -xsize * aspect) },
417     { Vector2(  xsize, -xsize * aspect) },
418     { Vector2( -xsize,  xsize * aspect) },
419     { Vector2(  xsize,  xsize * aspect) }
420   };
421
422   VertexTexture textures[] = {
423     { Vector2(0.0f, 0.0f) },
424     { Vector2(1.0f, 0.0f) },
425     { Vector2(0.0f, 1.0f) },
426     { Vector2(1.0f, 1.0f) }
427   };
428
429   unsigned int numberOfVertices = sizeof(vertices)/sizeof(VertexPosition);
430
431   //Vertices
432   Property::Map positionVertexFormat;
433   positionVertexFormat["aPosition"] = Property::VECTOR2;
434   PropertyBuffer positionVertices = PropertyBuffer::New( positionVertexFormat );
435   positionVertices.SetData( vertices, numberOfVertices );
436
437   //Textures
438   Property::Map textureVertexFormat;
439   textureVertexFormat["aTexture"] = Property::VECTOR2;
440   PropertyBuffer textureVertices = PropertyBuffer::New( textureVertexFormat );
441   textureVertices.SetData( textures, numberOfVertices );
442
443   //Indices
444   unsigned short indices[] = { 0, 3, 1, 0, 2, 3 };
445
446   // Create the geometry object
447   Geometry texturedQuadGeometry = Geometry::New();
448   texturedQuadGeometry.AddVertexBuffer( positionVertices );
449   texturedQuadGeometry.AddVertexBuffer( textureVertices );
450
451   texturedQuadGeometry.SetIndexBuffer ( &indices[0], sizeof( indices )/ sizeof( indices[0] ) );
452
453   return texturedQuadGeometry;
454 }
455
456 float randomNumber(float lowest, float highest)
457 {
458   float range=(highest-lowest);
459   return lowest+range*rand()/RAND_MAX;
460 }
461
462 void MetaballExplosionController::CreateMetaballActors()
463 {
464   //Create the shader for the metaballs
465   Shader shader = Shader::New( METABALL_VERTEX_SHADER, METABALL_FRAG_SHADER );
466
467   Geometry metaballGeom = CreateGeometry();
468   Renderer renderer = Renderer::New( metaballGeom, shader );
469   renderer.SetProperty( Renderer::Property::BLEND_MODE, BlendMode::ON );
470   renderer.SetProperty( Renderer::Property::BLEND_FACTOR_SRC_RGB,    BlendFactor::ONE );
471   renderer.SetProperty( Renderer::Property::BLEND_FACTOR_DEST_RGB,   BlendFactor::ONE );
472   renderer.SetProperty( Renderer::Property::BLEND_FACTOR_SRC_ALPHA,  BlendFactor::ONE );
473   renderer.SetProperty( Renderer::Property::BLEND_FACTOR_DEST_ALPHA, BlendFactor::ONE  );
474
475   //Initialization of each of the metaballs
476   for( int i = 0; i < METABALL_NUMBER; i++ )
477   {
478     mMetaballs[i].position = Vector2(0.0f, 0.0f);
479     mMetaballs[i].radius = mMetaballs[i].initRadius = randomNumber(0.05f,0.07f);
480
481     mMetaballs[i].actor = Actor::New( );
482     mMetaballs[i].actor.SetName("Metaball");
483     mMetaballs[i].actor.SetScale( 1.0f );
484     mMetaballs[i].actor.SetParentOrigin( ParentOrigin::CENTER );
485     mMetaballs[i].actor.AddRenderer( renderer );
486
487     mMetaballs[i].positionIndex = mMetaballs[i].actor.RegisterProperty( "uPositionMetaball", mMetaballs[i].position );
488
489     mMetaballs[i].positionVarIndex = mMetaballs[i].actor.RegisterProperty( "uPositionVar", Vector2(0.f,0.f) );
490
491     mMetaballs[i].actor.RegisterProperty( "uGravityVector", Vector2(randomNumber(-0.2,0.2),randomNumber(-0.2,0.2)) );
492
493     mMetaballs[i].actor.RegisterProperty( "uRadius", mMetaballs[i].radius );
494
495     mMetaballs[i].actor.RegisterProperty( "uRadiusVar", 0.f );
496
497     mMetaballs[i].actor.SetSize(400, 400);
498   }
499
500   //Root creation
501   mMetaballRoot = Actor::New();
502   mMetaballRoot.SetParentOrigin( ParentOrigin::CENTER );
503   for( int i = 0; i < METABALL_NUMBER; i++ )
504   {
505     mMetaballRoot.Add( mMetaballs[i].actor );
506   }
507
508   //Initialization of variables related to metaballs
509   mMetaballPosVariation = Vector2(0,0);
510   mMetaballPosVariationFrom = Vector2(0,0);
511   mMetaballPosVariationTo = Vector2(0,0);
512   mCurrentTouchPosition = Vector2(0,0);
513 }
514
515 void MetaballExplosionController::CreateMetaballImage()
516 {
517   //We create an FBO and a render task to create to render the metaballs with a fragment shader
518   Stage stage = Stage::GetCurrent();
519   mMetaballFBO = FrameBufferImage::New(mScreenSize.x, mScreenSize.y, Pixel::RGBA8888, RenderBuffer::COLOR_DEPTH);
520
521
522   stage.Add(mMetaballRoot);
523
524   //Creation of the render task used to render the metaballs
525   RenderTaskList taskList = Stage::GetCurrent().GetRenderTaskList();
526   RenderTask task = taskList.CreateTask();
527   task.SetRefreshRate( RenderTask::REFRESH_ALWAYS );
528   task.SetSourceActor( mMetaballRoot );
529   task.SetExclusive(true);
530   task.SetClearColor( Color::BLACK );
531   task.SetClearEnabled( true );
532   task.SetTargetFrameBuffer( mMetaballFBO );
533 }
534
535 void MetaballExplosionController::AddRefractionImage()
536 {
537   //Create Gaussian blur for the rendered image
538   FrameBufferImage fbo;
539   fbo = FrameBufferImage::New( mScreenSize.x, mScreenSize.y, Pixel::RGBA8888, RenderBuffer::COLOR_DEPTH);
540
541   GaussianBlurView gbv = GaussianBlurView::New(5, 2.0f, Pixel::RGBA8888, 0.5f, 0.5f, true);
542   gbv.SetBackgroundColor(Color::TRANSPARENT);
543   gbv.SetUserImageAndOutputRenderTarget( mMetaballFBO, fbo );
544   gbv.SetSize(mScreenSize.x, mScreenSize.y);
545   Stage::GetCurrent().Add(gbv);
546   gbv.Activate();
547
548   //Create new shader
549   Shader shader = Shader::New( METABALL_VERTEX_SHADER, REFRACTION_FRAG_SHADER );
550
551   //Create new texture set
552   TextureSet textureSet = TextureSet::New();
553   textureSet.SetImage( 0u, mBackImage );
554   textureSet.SetImage( 1u, fbo );
555
556   //Create geometry
557   Geometry metaballGeom = CreateGeometryComposition();
558
559   Renderer mRenderer = Renderer::New( metaballGeom, shader );
560   mRenderer.SetTextures( textureSet );
561
562   mCompositionActor = Actor::New( );
563   mCompositionActor.SetParentOrigin(ParentOrigin::CENTER);
564   mCompositionActor.SetPosition(Vector3(0.0f, 0.0f, 0.0f));
565   mCompositionActor.SetSize(mScreenSize.x, mScreenSize.y);
566
567   mCompositionActor.AddRenderer( mRenderer );
568
569   Vector2 metaballCenter(0.0,0);
570   metaballCenter.x = metaballCenter.x * 0.5;
571   metaballCenter.y = metaballCenter.y * 0.5;
572
573   mPositionIndex = mCompositionActor.RegisterProperty( "uPositionMetaball", metaballCenter );
574
575   SetPositionToMetaballs(metaballCenter);
576
577   mCompositionActor.SetSize(mScreenSize.x, mScreenSize.y);
578
579   Stage stage = Stage::GetCurrent();
580   stage.Add( mCompositionActor );
581 }
582
583 void MetaballExplosionController::CreateAnimations()
584 {
585   Vector2 direction;
586
587   for( int i = 0; i < METABALL_NUMBER; i++ )
588   {
589     float key;
590     KeyFrames keySinCosVariation = KeyFrames::New();
591     Vector2 sinCosVariation(0,0);
592
593     direction.x = randomNumber(-100.f,100.f);
594     direction.y = randomNumber(-100.f,100.f);
595
596     direction.Normalize();
597     direction *= 0.1f;
598
599     for( int j = 0; j < 360; j++ )
600     {
601       sinCosVariation.x = sin(j * Math::PI/180.f) * direction.x;
602       sinCosVariation.y = cos(j * Math::PI/180.f) * direction.y;
603       key = j/360.f;
604       keySinCosVariation.Add(key, sinCosVariation);
605     }
606
607     mPositionVarAnimation[i] = Animation::New(3.f);
608     mPositionVarAnimation[i].AnimateBetween(Property( mMetaballs[i].actor, mMetaballs[i].positionVarIndex ), keySinCosVariation);
609     mPositionVarAnimation[i].SetLooping( true );
610     mPositionVarAnimation[i].Play();
611   }
612 }
613
614 void MetaballExplosionController::ResetMetaballs(bool resetAnims)
615 {
616   for( int i = 0; i < METABALL_NUMBER; i++ )
617   {
618     if (mDispersionAnimation[i])
619       mDispersionAnimation[i].Clear();
620
621     mMetaballs[i].position = Vector2(0.0f, 0.0f);
622     mMetaballs[i].actor.SetProperty(mMetaballs[i].positionIndex, mMetaballs[i].position);
623   }
624   mTimerDispersion.Stop();
625   mDispersion = 0;
626
627   mCompositionActor.SetProperty( mPositionIndex, Vector2(0,0) );
628 }
629
630 void MetaballExplosionController::DisperseBallAnimation(int ball)
631 {
632   Vector2 position;
633   position.x = randomNumber(-1.5f,1.5f);
634   position.y = randomNumber(-1.5f,1.5f);
635
636   mDispersionAnimation[ball] = Animation::New(2.0f * mTimeMult);
637   mDispersionAnimation[ball].AnimateTo( Property(mMetaballs[ball].actor, mMetaballs[ball].positionIndex), position);
638   mDispersionAnimation[ball].Play();
639
640   if( ball == METABALL_NUMBER - 1 )
641     mDispersionAnimation[ball].FinishedSignal().Connect( this, &MetaballExplosionController::LaunchResetMetaballPosition );
642 }
643
644 void MetaballExplosionController::LaunchResetMetaballPosition(Animation &source)
645 {
646   for( int i = 0; i < METABALL_NUMBER; i++ )
647   {
648     mDispersionAnimation[i] = Animation::New(1.5f + i*0.25f*mTimeMult);
649     mDispersionAnimation[i].AnimateTo(Property(mMetaballs[i].actor, mMetaballs[i].positionIndex), Vector2(0,0));
650     mDispersionAnimation[i].Play();
651
652     if( i == METABALL_NUMBER - 1 )
653       mDispersionAnimation[i].FinishedSignal().Connect( this, &MetaballExplosionController::EndDisperseAnimation );
654   }
655 }
656
657 void MetaballExplosionController::EndDisperseAnimation(Animation &source)
658 {
659   mCompositionActor.SetProperty( mPositionIndex, Vector2(0,0) );
660 }
661
662 bool MetaballExplosionController::OnTimerDispersionTick()
663 {
664   if( mDispersion < METABALL_NUMBER )
665   {
666     DisperseBallAnimation(mDispersion);
667     mDispersion++;
668   }
669   return true;
670 }
671
672 void MetaballExplosionController::SetPositionToMetaballs(Vector2 & metaballCenter)
673 {
674   //We set the position for the metaballs based on click position
675   for( int i = 0; i < METABALL_NUMBER; i++ )
676   {
677     mMetaballs[i].position = metaballCenter;
678     mMetaballs[i].actor.SetProperty(mMetaballs[i].positionIndex, mMetaballs[i].position);
679   }
680
681   mCompositionActor.SetProperty( mPositionIndex, metaballCenter );
682 }
683
684 bool MetaballExplosionController::OnTouch( Actor actor, const TouchData& touch )
685 {
686   float aspectR = mScreenSize.y / mScreenSize.x;
687
688   switch( touch.GetState( 0 ) )
689   {
690     case PointState::DOWN:
691     {
692       ResetMetaballs(true);
693
694       const Vector2 screen = touch.GetScreenPosition( 0 );
695       Vector2 metaballCenter = Vector2((screen.x / mScreenSize.x) - 0.5, (aspectR * (mScreenSize.y - screen.y) / mScreenSize.y) - 0.5) * 2.0;
696       SetPositionToMetaballs(metaballCenter);
697
698       break;
699     }
700     case PointState::MOTION:
701     {
702       const Vector2 screen = touch.GetScreenPosition( 0 );
703       Vector2 metaballCenter = Vector2((screen.x / mScreenSize.x) - 0.5, (aspectR * (mScreenSize.y - screen.y) / mScreenSize.y) - 0.5) * 2.0;
704       SetPositionToMetaballs(metaballCenter);
705       break;
706     }
707     case PointState::UP:
708     case PointState::LEAVE:
709     case PointState::INTERRUPTED:
710     {
711       mTimerDispersion.Start();
712       break;
713     }
714     default:
715       break;
716     }
717   return true;
718 }
719
720 void MetaballExplosionController::OnKeyEvent(const KeyEvent& event)
721 {
722   if(event.state == KeyEvent::Down)
723   {
724     if( IsKey( event, Dali::DALI_KEY_ESCAPE) || IsKey( event, Dali::DALI_KEY_BACK) )
725     {
726       mApplication.Quit();
727     }
728   }
729 }
730
731
732 //-----------------------------------------------------------------------------------------------
733 //
734 //  Main functions
735 //
736 //-----------------------------------------------------------------------------------------------
737
738 void RunTest( Application& application )
739 {
740   MetaballExplosionController test( application );
741
742   application.MainLoop();
743 }
744
745 // Entry point for Linux & Tizen applications
746 //
747 int DALI_EXPORT_API main( int argc, char **argv )
748 {
749   Application application = Application::New( &argc, &argv );
750
751   RunTest( application );
752
753   return 0;
754 }