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