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