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