Improve application launching speed
[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 TouchEvent& 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().TouchedSignal().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   int indices[] = { 0, 3, 1, 0, 2, 3 };
377
378   unsigned int numberOfVertices = sizeof(vertices)/sizeof(VertexPosition);
379
380   //Vertices
381   Property::Map positionVertexFormat;
382   positionVertexFormat["aPosition"] = Property::VECTOR2;
383   PropertyBuffer positionVertices = PropertyBuffer::New( positionVertexFormat );
384   positionVertices.SetData( vertices, numberOfVertices );
385
386   //Textures
387   Property::Map textureVertexFormat;
388   textureVertexFormat["aTexture"] = Property::VECTOR2;
389   PropertyBuffer textureVertices = PropertyBuffer::New( textureVertexFormat );
390   textureVertices.SetData( textures, numberOfVertices );
391
392   //Indices
393   Property::Map indicesVertexFormat;
394   indicesVertexFormat["aIndices"] = Property::INTEGER;
395   PropertyBuffer indicesToVertices = PropertyBuffer::New( indicesVertexFormat );
396   indicesToVertices.SetData( indices, 6 );
397
398   // Create the geometry object
399   Geometry texturedQuadGeometry = Geometry::New();
400   texturedQuadGeometry.AddVertexBuffer( positionVertices );
401   texturedQuadGeometry.AddVertexBuffer( textureVertices );
402
403   texturedQuadGeometry.SetIndexBuffer ( indicesToVertices );
404
405   return texturedQuadGeometry;
406 }
407
408 Geometry MetaballExplosionController::CreateGeometryComposition()
409 {
410   float aspect = (float)mScreenSize.y / (float)mScreenSize.x;
411
412   // Create vertices and specify their color
413   float xsize = mScreenSize.x * 0.5;
414
415   //We create the meshdata for the metaballs
416   struct VertexPosition { Vector2 position; };
417   struct VertexTexture { Vector2 texture; };
418   struct VertexNormal { Vector3 normal; };
419
420   VertexPosition vertices[] = {
421     { Vector2( -xsize, -xsize * aspect) },
422     { Vector2(  xsize, -xsize * aspect) },
423     { Vector2( -xsize,  xsize * aspect) },
424     { Vector2(  xsize,  xsize * aspect) }
425   };
426
427   VertexTexture textures[] = {
428     { Vector2(0.0f, 0.0f) },
429     { Vector2(1.0f, 0.0f) },
430     { Vector2(0.0f, 1.0f) },
431     { Vector2(1.0f, 1.0f) }
432   };
433
434   int indices[] = { 0, 3, 1, 0, 2, 3 };
435
436   unsigned int numberOfVertices = sizeof(vertices)/sizeof(VertexPosition);
437
438   //Vertices
439   Property::Map positionVertexFormat;
440   positionVertexFormat["aPosition"] = Property::VECTOR2;
441   PropertyBuffer positionVertices = PropertyBuffer::New( positionVertexFormat );
442   positionVertices.SetData( vertices, numberOfVertices );
443
444   //Textures
445   Property::Map textureVertexFormat;
446   textureVertexFormat["aTexture"] = Property::VECTOR2;
447   PropertyBuffer textureVertices = PropertyBuffer::New( textureVertexFormat );
448   textureVertices.SetData( textures, numberOfVertices );
449
450   //Indices
451   Property::Map indicesVertexFormat;
452   indicesVertexFormat["aIndices"] = Property::INTEGER;
453   PropertyBuffer indicesToVertices = PropertyBuffer::New( indicesVertexFormat );
454   indicesToVertices.SetData( indices, 6 );
455
456   // Create the geometry object
457   Geometry texturedQuadGeometry = Geometry::New();
458   texturedQuadGeometry.AddVertexBuffer( positionVertices );
459   texturedQuadGeometry.AddVertexBuffer( textureVertices );
460
461   texturedQuadGeometry.SetIndexBuffer ( indicesToVertices );
462
463   return texturedQuadGeometry;
464 }
465
466 float randomNumber(float lowest, float highest)
467 {
468   float range=(highest-lowest);
469   return lowest+range*rand()/RAND_MAX;
470 }
471
472 void MetaballExplosionController::CreateMetaballActors()
473 {
474   //Create the shader for the metaballs
475   Shader shader = Shader::New( METABALL_VERTEX_SHADER, METABALL_FRAG_SHADER );
476
477   Geometry metaballGeom = CreateGeometry();
478   Renderer renderer = Renderer::New( metaballGeom, shader );
479   renderer.SetProperty( Renderer::Property::BLENDING_MODE, BlendingMode::ON );
480   renderer.SetBlendFunc(BlendingFactor::ONE, BlendingFactor::ONE, BlendingFactor::ONE, BlendingFactor::ONE);
481   //Initialization of each of the metaballs
482   for( int i = 0; i < METABALL_NUMBER; i++ )
483   {
484     mMetaballs[i].position = Vector2(0.0f, 0.0f);
485     mMetaballs[i].radius = mMetaballs[i].initRadius = randomNumber(0.05f,0.07f);
486
487     mMetaballs[i].actor = Actor::New( );
488     mMetaballs[i].actor.SetName("Metaball");
489     mMetaballs[i].actor.SetScale( 1.0f );
490     mMetaballs[i].actor.SetParentOrigin( ParentOrigin::CENTER );
491     mMetaballs[i].actor.AddRenderer( renderer );
492
493     mMetaballs[i].positionIndex = mMetaballs[i].actor.RegisterProperty( "uPositionMetaball", mMetaballs[i].position );
494
495     mMetaballs[i].positionVarIndex = mMetaballs[i].actor.RegisterProperty( "uPositionVar", Vector2(0.f,0.f) );
496
497     mMetaballs[i].actor.RegisterProperty( "uGravityVector", Vector2(randomNumber(-0.2,0.2),randomNumber(-0.2,0.2)) );
498
499     mMetaballs[i].actor.RegisterProperty( "uRadius", mMetaballs[i].radius );
500
501     mMetaballs[i].actor.RegisterProperty( "uRadiusVar", 0.f );
502
503     mMetaballs[i].actor.SetSize(400, 400);
504   }
505
506   //Root creation
507   mMetaballRoot = Actor::New();
508   mMetaballRoot.SetParentOrigin( ParentOrigin::CENTER );
509   for( int i = 0; i < METABALL_NUMBER; i++ )
510   {
511     mMetaballRoot.Add( mMetaballs[i].actor );
512   }
513
514   //Initialization of variables related to metaballs
515   mMetaballPosVariation = Vector2(0,0);
516   mMetaballPosVariationFrom = Vector2(0,0);
517   mMetaballPosVariationTo = Vector2(0,0);
518   mCurrentTouchPosition = Vector2(0,0);
519 }
520
521 void MetaballExplosionController::CreateMetaballImage()
522 {
523   //We create an FBO and a render task to create to render the metaballs with a fragment shader
524   Stage stage = Stage::GetCurrent();
525   mMetaballFBO = FrameBufferImage::New(mScreenSize.x, mScreenSize.y, Pixel::RGBA8888, RenderBuffer::COLOR_DEPTH);
526
527
528   stage.Add(mMetaballRoot);
529
530   //Creation of the render task used to render the metaballs
531   RenderTaskList taskList = Stage::GetCurrent().GetRenderTaskList();
532   RenderTask task = taskList.CreateTask();
533   task.SetRefreshRate( RenderTask::REFRESH_ALWAYS );
534   task.SetSourceActor( mMetaballRoot );
535   task.SetExclusive(true);
536   task.SetClearColor( Color::BLACK );
537   task.SetClearEnabled( true );
538   task.SetTargetFrameBuffer( mMetaballFBO );
539 }
540
541 void MetaballExplosionController::AddRefractionImage()
542 {
543   //Create Gaussian blur for the rendered image
544   FrameBufferImage fbo;
545   fbo = FrameBufferImage::New( mScreenSize.x, mScreenSize.y, Pixel::RGBA8888, RenderBuffer::COLOR_DEPTH);
546
547   GaussianBlurView gbv = GaussianBlurView::New(5, 2.0f, Pixel::RGBA8888, 0.5f, 0.5f, true);
548   gbv.SetBackgroundColor(Color::TRANSPARENT);
549   gbv.SetUserImageAndOutputRenderTarget( mMetaballFBO, fbo );
550   gbv.SetSize(mScreenSize.x, mScreenSize.y);
551   Stage::GetCurrent().Add(gbv);
552   gbv.Activate();
553
554   //Create new shader
555   Shader shader = Shader::New( METABALL_VERTEX_SHADER, REFRACTION_FRAG_SHADER );
556
557   //Create new texture set
558   TextureSet textureSet = TextureSet::New();
559   textureSet.SetImage( 0u, mBackImage );
560   textureSet.SetImage( 1u, fbo );
561
562   //Create geometry
563   Geometry metaballGeom = CreateGeometryComposition();
564
565   Renderer mRenderer = Renderer::New( metaballGeom, shader );
566   mRenderer.SetTextures( textureSet );
567
568   mCompositionActor = Actor::New( );
569   mCompositionActor.SetParentOrigin(ParentOrigin::CENTER);
570   mCompositionActor.SetPosition(Vector3(0.0f, 0.0f, 0.0f));
571   mCompositionActor.SetSize(mScreenSize.x, mScreenSize.y);
572
573   mCompositionActor.AddRenderer( mRenderer );
574
575   Vector2 metaballCenter(0.0,0);
576   metaballCenter.x = metaballCenter.x * 0.5;
577   metaballCenter.y = metaballCenter.y * 0.5;
578
579   mPositionIndex = mCompositionActor.RegisterProperty( "uPositionMetaball", metaballCenter );
580
581   SetPositionToMetaballs(metaballCenter);
582
583   mCompositionActor.SetSize(mScreenSize.x, mScreenSize.y);
584
585   Stage stage = Stage::GetCurrent();
586   stage.Add( mCompositionActor );
587 }
588
589 void MetaballExplosionController::CreateAnimations()
590 {
591   Vector2 direction;
592
593   for( int i = 0; i < METABALL_NUMBER; i++ )
594   {
595     float key;
596     KeyFrames keySinCosVariation = KeyFrames::New();
597     Vector2 sinCosVariation(0,0);
598
599     direction.x = randomNumber(-100.f,100.f);
600     direction.y = randomNumber(-100.f,100.f);
601
602     direction.Normalize();
603     direction *= 0.1f;
604
605     for( int j = 0; j < 360; j++ )
606     {
607       sinCosVariation.x = sin(j * Math::PI/180.f) * direction.x;
608       sinCosVariation.y = cos(j * Math::PI/180.f) * direction.y;
609       key = j/360.f;
610       keySinCosVariation.Add(key, sinCosVariation);
611     }
612
613     mPositionVarAnimation[i] = Animation::New(3.f);
614     mPositionVarAnimation[i].AnimateBetween(Property( mMetaballs[i].actor, mMetaballs[i].positionVarIndex ), keySinCosVariation);
615     mPositionVarAnimation[i].SetLooping( true );
616     mPositionVarAnimation[i].Play();
617   }
618 }
619
620 void MetaballExplosionController::ResetMetaballs(bool resetAnims)
621 {
622   for( int i = 0; i < METABALL_NUMBER; i++ )
623   {
624     if (mDispersionAnimation[i])
625       mDispersionAnimation[i].Clear();
626
627     mMetaballs[i].position = Vector2(0.0f, 0.0f);
628     mMetaballs[i].actor.SetProperty(mMetaballs[i].positionIndex, mMetaballs[i].position);
629   }
630   mTimerDispersion.Stop();
631   mDispersion = 0;
632
633   mCompositionActor.SetProperty( mPositionIndex, Vector2(0,0) );
634 }
635
636 void MetaballExplosionController::DisperseBallAnimation(int ball)
637 {
638   Vector2 position;
639   position.x = randomNumber(-1.5f,1.5f);
640   position.y = randomNumber(-1.5f,1.5f);
641
642   mDispersionAnimation[ball] = Animation::New(2.0f * mTimeMult);
643   mDispersionAnimation[ball].AnimateTo( Property(mMetaballs[ball].actor, mMetaballs[ball].positionIndex), position);
644   mDispersionAnimation[ball].Play();
645
646   if( ball == METABALL_NUMBER - 1 )
647     mDispersionAnimation[ball].FinishedSignal().Connect( this, &MetaballExplosionController::LaunchResetMetaballPosition );
648 }
649
650 void MetaballExplosionController::LaunchResetMetaballPosition(Animation &source)
651 {
652   for( int i = 0; i < METABALL_NUMBER; i++ )
653   {
654     mDispersionAnimation[i] = Animation::New(1.5f + i*0.25f*mTimeMult);
655     mDispersionAnimation[i].AnimateTo(Property(mMetaballs[i].actor, mMetaballs[i].positionIndex), Vector2(0,0));
656     mDispersionAnimation[i].Play();
657
658     if( i == METABALL_NUMBER - 1 )
659       mDispersionAnimation[i].FinishedSignal().Connect( this, &MetaballExplosionController::EndDisperseAnimation );
660   }
661 }
662
663 void MetaballExplosionController::EndDisperseAnimation(Animation &source)
664 {
665   mCompositionActor.SetProperty( mPositionIndex, Vector2(0,0) );
666 }
667
668 bool MetaballExplosionController::OnTimerDispersionTick()
669 {
670   if( mDispersion < METABALL_NUMBER )
671   {
672     DisperseBallAnimation(mDispersion);
673     mDispersion++;
674   }
675   return true;
676 }
677
678 void MetaballExplosionController::SetPositionToMetaballs(Vector2 & metaballCenter)
679 {
680   //We set the position for the metaballs based on click position
681   for( int i = 0; i < METABALL_NUMBER; i++ )
682   {
683     mMetaballs[i].position = metaballCenter;
684     mMetaballs[i].actor.SetProperty(mMetaballs[i].positionIndex, mMetaballs[i].position);
685   }
686
687   mCompositionActor.SetProperty( mPositionIndex, metaballCenter );
688 }
689
690 bool MetaballExplosionController::OnTouch( Actor actor, const TouchEvent& touch )
691 {
692   const TouchPoint &point = touch.GetPoint(0);
693   float aspectR = mScreenSize.y / mScreenSize.x;
694
695   switch( point.state )
696   {
697     case TouchPoint::Down:
698     {
699       ResetMetaballs(true);
700
701       Vector2 metaballCenter = Vector2((point.screen.x / mScreenSize.x) - 0.5, (aspectR * (mScreenSize.y - point.screen.y) / mScreenSize.y) - 0.5) * 2.0;
702       SetPositionToMetaballs(metaballCenter);
703
704       break;
705     }
706     case TouchPoint::Motion:
707     {
708       Vector2 metaballCenter = Vector2((point.screen.x / mScreenSize.x) - 0.5, (aspectR * (mScreenSize.y - point.screen.y) / mScreenSize.y) - 0.5) * 2.0;
709       SetPositionToMetaballs(metaballCenter);
710       break;
711     }
712     case TouchPoint::Up:
713     case TouchPoint::Leave:
714     case TouchPoint::Interrupted:
715     {
716       mTimerDispersion.Start();
717       break;
718     }
719     default:
720       break;
721     }
722   return true;
723 }
724
725 void MetaballExplosionController::OnKeyEvent(const KeyEvent& event)
726 {
727   if(event.state == KeyEvent::Down)
728   {
729     if( IsKey( event, Dali::DALI_KEY_ESCAPE) || IsKey( event, Dali::DALI_KEY_BACK) )
730     {
731       mApplication.Quit();
732     }
733   }
734 }
735
736
737 //-----------------------------------------------------------------------------------------------
738 //
739 //  Main functions
740 //
741 //-----------------------------------------------------------------------------------------------
742
743 void RunTest( Application& application )
744 {
745   MetaballExplosionController test( application );
746
747   application.MainLoop();
748 }
749
750 // Entry point for Linux & Tizen applications
751 //
752 int DALI_EXPORT_API main( int argc, char **argv )
753 {
754   Application application = Application::New( &argc, &argv );
755
756   RunTest( application );
757
758   return 0;
759 }