Moved TextureSet::SetImage() to separate devel-api module
[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
22 //Internal includes
23 #include <dali/dali.h>
24 #include <dali/devel-api/images/texture-set-image.h>
25 #include <dali/devel-api/rendering/renderer.h>
26 #include <dali-toolkit/dali-toolkit.h>
27
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 {
311   // Connect to the Application's Init signal
312   mApplication.InitSignal().Connect( this, &MetaballExplosionController::Create );
313 }
314
315 MetaballExplosionController::~MetaballExplosionController()
316 {
317   // Nothing to do here;
318 }
319
320 void MetaballExplosionController::Create( Application& app )
321 {
322   Stage stage = Stage::GetCurrent();
323
324   stage.KeyEventSignal().Connect(this, &MetaballExplosionController::OnKeyEvent);
325
326   mScreenSize = stage.GetSize();
327
328   mTimeMult = 1.0f;
329
330   stage.SetBackgroundColor(Color::BLACK);
331
332   //Set background image for the view
333   mBackImage = DemoHelper::LoadImage( BACKGROUND_IMAGE );
334
335   srand((unsigned)time(0));
336
337   //Create internal data
338   CreateMetaballActors();
339   CreateMetaballImage();
340   AddRefractionImage();
341
342   CreateAnimations();
343
344   mDispersion = 0;
345   mTimerDispersion = Timer::New( 150 );
346   mTimerDispersion.TickSignal().Connect(this, &MetaballExplosionController::OnTimerDispersionTick);
347
348   // Connect the callback to the touch signal on the mesh actor
349   stage.GetRootLayer().TouchSignal().Connect( this, &MetaballExplosionController::OnTouch );
350 }
351
352 Geometry MetaballExplosionController::CreateGeometry()
353 {
354   float aspect = (float)mScreenSize.y / (float)mScreenSize.x;
355
356   // Create vertices and specify their color
357   float xsize = mScreenSize.x * 0.5;
358
359   //We create the meshdata for the metaballs
360   struct VertexPosition { Vector2 position; };
361   struct VertexTexture { Vector2 texture; };
362   struct VertexNormal { Vector3 normal; };
363
364   VertexPosition vertices[] = {
365     { Vector2( -xsize, -xsize * aspect) },
366     { Vector2(  xsize, -xsize * aspect) },
367     { Vector2( -xsize,  xsize * aspect) },
368     { Vector2(  xsize,  xsize * aspect) }
369   };
370
371   VertexTexture textures[] = {
372     { Vector2(0.0f, 0.0f) },
373     { Vector2(1.0f, 0.0f) },
374     { Vector2(0.0f, 1.0f * aspect) },
375     { Vector2(1.0f, 1.0f * aspect) }
376   };
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   unsigned short indices[] = { 0, 3, 1, 0, 2, 3 };
394
395   // Create the geometry object
396   Geometry texturedQuadGeometry = Geometry::New();
397   texturedQuadGeometry.AddVertexBuffer( positionVertices );
398   texturedQuadGeometry.AddVertexBuffer( textureVertices );
399
400   texturedQuadGeometry.SetIndexBuffer ( &indices[0], sizeof( indices )/ sizeof( indices[0] ) );
401
402   return texturedQuadGeometry;
403 }
404
405 Geometry MetaballExplosionController::CreateGeometryComposition()
406 {
407   float aspect = (float)mScreenSize.y / (float)mScreenSize.x;
408
409   // Create vertices and specify their color
410   float xsize = mScreenSize.x * 0.5;
411
412   //We create the meshdata for the metaballs
413   struct VertexPosition { Vector2 position; };
414   struct VertexTexture { Vector2 texture; };
415   struct VertexNormal { Vector3 normal; };
416
417   VertexPosition vertices[] = {
418     { Vector2( -xsize, -xsize * aspect) },
419     { Vector2(  xsize, -xsize * aspect) },
420     { Vector2( -xsize,  xsize * aspect) },
421     { Vector2(  xsize,  xsize * aspect) }
422   };
423
424   VertexTexture textures[] = {
425     { Vector2(0.0f, 0.0f) },
426     { Vector2(1.0f, 0.0f) },
427     { Vector2(0.0f, 1.0f) },
428     { Vector2(1.0f, 1.0f) }
429   };
430
431   unsigned int numberOfVertices = sizeof(vertices)/sizeof(VertexPosition);
432
433   //Vertices
434   Property::Map positionVertexFormat;
435   positionVertexFormat["aPosition"] = Property::VECTOR2;
436   PropertyBuffer positionVertices = PropertyBuffer::New( positionVertexFormat );
437   positionVertices.SetData( vertices, numberOfVertices );
438
439   //Textures
440   Property::Map textureVertexFormat;
441   textureVertexFormat["aTexture"] = Property::VECTOR2;
442   PropertyBuffer textureVertices = PropertyBuffer::New( textureVertexFormat );
443   textureVertices.SetData( textures, numberOfVertices );
444
445   //Indices
446   unsigned short indices[] = { 0, 3, 1, 0, 2, 3 };
447
448   // Create the geometry object
449   Geometry texturedQuadGeometry = Geometry::New();
450   texturedQuadGeometry.AddVertexBuffer( positionVertices );
451   texturedQuadGeometry.AddVertexBuffer( textureVertices );
452
453   texturedQuadGeometry.SetIndexBuffer ( &indices[0], sizeof( indices )/ sizeof( indices[0] ) );
454
455   return texturedQuadGeometry;
456 }
457
458 float randomNumber(float lowest, float highest)
459 {
460   float range=(highest-lowest);
461   return lowest+range*rand()/RAND_MAX;
462 }
463
464 void MetaballExplosionController::CreateMetaballActors()
465 {
466   //Create the shader for the metaballs
467   Shader shader = Shader::New( METABALL_VERTEX_SHADER, METABALL_FRAG_SHADER );
468
469   Geometry metaballGeom = CreateGeometry();
470   Renderer renderer = Renderer::New( metaballGeom, shader );
471   renderer.SetProperty( Renderer::Property::BLEND_MODE, BlendMode::ON );
472   renderer.SetProperty( Renderer::Property::BLEND_FACTOR_SRC_RGB,    BlendFactor::ONE );
473   renderer.SetProperty( Renderer::Property::BLEND_FACTOR_DEST_RGB,   BlendFactor::ONE );
474   renderer.SetProperty( Renderer::Property::BLEND_FACTOR_SRC_ALPHA,  BlendFactor::ONE );
475   renderer.SetProperty( Renderer::Property::BLEND_FACTOR_DEST_ALPHA, BlendFactor::ONE  );
476
477   //Initialization of each of the metaballs
478   for( int i = 0; i < METABALL_NUMBER; i++ )
479   {
480     mMetaballs[i].position = Vector2(0.0f, 0.0f);
481     mMetaballs[i].radius = mMetaballs[i].initRadius = randomNumber(0.05f,0.07f);
482
483     mMetaballs[i].actor = Actor::New( );
484     mMetaballs[i].actor.SetName("Metaball");
485     mMetaballs[i].actor.SetScale( 1.0f );
486     mMetaballs[i].actor.SetParentOrigin( ParentOrigin::CENTER );
487     mMetaballs[i].actor.AddRenderer( renderer );
488
489     mMetaballs[i].positionIndex = mMetaballs[i].actor.RegisterProperty( "uPositionMetaball", mMetaballs[i].position );
490
491     mMetaballs[i].positionVarIndex = mMetaballs[i].actor.RegisterProperty( "uPositionVar", Vector2(0.f,0.f) );
492
493     mMetaballs[i].actor.RegisterProperty( "uGravityVector", Vector2(randomNumber(-0.2,0.2),randomNumber(-0.2,0.2)) );
494
495     mMetaballs[i].actor.RegisterProperty( "uRadius", mMetaballs[i].radius );
496
497     mMetaballs[i].actor.RegisterProperty( "uRadiusVar", 0.f );
498
499     mMetaballs[i].actor.SetSize(400, 400);
500   }
501
502   //Root creation
503   mMetaballRoot = Actor::New();
504   mMetaballRoot.SetParentOrigin( ParentOrigin::CENTER );
505   for( int i = 0; i < METABALL_NUMBER; i++ )
506   {
507     mMetaballRoot.Add( mMetaballs[i].actor );
508   }
509
510   //Initialization of variables related to metaballs
511   mMetaballPosVariation = Vector2(0,0);
512   mMetaballPosVariationFrom = Vector2(0,0);
513   mMetaballPosVariationTo = Vector2(0,0);
514   mCurrentTouchPosition = Vector2(0,0);
515 }
516
517 void MetaballExplosionController::CreateMetaballImage()
518 {
519   //We create an FBO and a render task to create to render the metaballs with a fragment shader
520   Stage stage = Stage::GetCurrent();
521   mMetaballFBO = FrameBufferImage::New(mScreenSize.x, mScreenSize.y, Pixel::RGBA8888, RenderBuffer::COLOR_DEPTH);
522
523
524   stage.Add(mMetaballRoot);
525
526   //Creation of the render task used to render the metaballs
527   RenderTaskList taskList = Stage::GetCurrent().GetRenderTaskList();
528   RenderTask task = taskList.CreateTask();
529   task.SetRefreshRate( RenderTask::REFRESH_ALWAYS );
530   task.SetSourceActor( mMetaballRoot );
531   task.SetExclusive(true);
532   task.SetClearColor( Color::BLACK );
533   task.SetClearEnabled( true );
534   task.SetTargetFrameBuffer( mMetaballFBO );
535 }
536
537 void MetaballExplosionController::AddRefractionImage()
538 {
539   //Create Gaussian blur for the rendered image
540   FrameBufferImage fbo;
541   fbo = FrameBufferImage::New( mScreenSize.x, mScreenSize.y, Pixel::RGBA8888, RenderBuffer::COLOR_DEPTH);
542
543   GaussianBlurView gbv = GaussianBlurView::New(5, 2.0f, Pixel::RGBA8888, 0.5f, 0.5f, true);
544   gbv.SetBackgroundColor(Color::TRANSPARENT);
545   gbv.SetUserImageAndOutputRenderTarget( mMetaballFBO, fbo );
546   gbv.SetSize(mScreenSize.x, mScreenSize.y);
547   Stage::GetCurrent().Add(gbv);
548   gbv.Activate();
549
550   //Create new shader
551   Shader shader = Shader::New( METABALL_VERTEX_SHADER, REFRACTION_FRAG_SHADER );
552
553   //Create new texture set
554   TextureSet textureSet = TextureSet::New();
555   TextureSetImage( textureSet, 0u, mBackImage );
556   TextureSetImage( textureSet, 1u, fbo );
557
558   //Create geometry
559   Geometry metaballGeom = CreateGeometryComposition();
560
561   Renderer mRenderer = Renderer::New( metaballGeom, shader );
562   mRenderer.SetTextures( textureSet );
563
564   mCompositionActor = Actor::New( );
565   mCompositionActor.SetParentOrigin(ParentOrigin::CENTER);
566   mCompositionActor.SetPosition(Vector3(0.0f, 0.0f, 0.0f));
567   mCompositionActor.SetSize(mScreenSize.x, mScreenSize.y);
568
569   mCompositionActor.AddRenderer( mRenderer );
570
571   Vector2 metaballCenter(0.0,0);
572   metaballCenter.x = metaballCenter.x * 0.5;
573   metaballCenter.y = metaballCenter.y * 0.5;
574
575   mPositionIndex = mCompositionActor.RegisterProperty( "uPositionMetaball", metaballCenter );
576
577   SetPositionToMetaballs(metaballCenter);
578
579   mCompositionActor.SetSize(mScreenSize.x, mScreenSize.y);
580
581   Stage stage = Stage::GetCurrent();
582   stage.Add( mCompositionActor );
583 }
584
585 void MetaballExplosionController::CreateAnimations()
586 {
587   Vector2 direction;
588
589   for( int i = 0; i < METABALL_NUMBER; i++ )
590   {
591     float key;
592     KeyFrames keySinCosVariation = KeyFrames::New();
593     Vector2 sinCosVariation(0,0);
594
595     direction.x = randomNumber(-100.f,100.f);
596     direction.y = randomNumber(-100.f,100.f);
597
598     direction.Normalize();
599     direction *= 0.1f;
600
601     for( int j = 0; j < 360; j++ )
602     {
603       sinCosVariation.x = sin(j * Math::PI/180.f) * direction.x;
604       sinCosVariation.y = cos(j * Math::PI/180.f) * direction.y;
605       key = j/360.f;
606       keySinCosVariation.Add(key, sinCosVariation);
607     }
608
609     mPositionVarAnimation[i] = Animation::New(3.f);
610     mPositionVarAnimation[i].AnimateBetween(Property( mMetaballs[i].actor, mMetaballs[i].positionVarIndex ), keySinCosVariation);
611     mPositionVarAnimation[i].SetLooping( true );
612     mPositionVarAnimation[i].Play();
613   }
614 }
615
616 void MetaballExplosionController::ResetMetaballs(bool resetAnims)
617 {
618   for( int i = 0; i < METABALL_NUMBER; i++ )
619   {
620     if (mDispersionAnimation[i])
621       mDispersionAnimation[i].Clear();
622
623     mMetaballs[i].position = Vector2(0.0f, 0.0f);
624     mMetaballs[i].actor.SetProperty(mMetaballs[i].positionIndex, mMetaballs[i].position);
625   }
626   mTimerDispersion.Stop();
627   mDispersion = 0;
628
629   mCompositionActor.SetProperty( mPositionIndex, Vector2(0,0) );
630 }
631
632 void MetaballExplosionController::DisperseBallAnimation(int ball)
633 {
634   Vector2 position;
635   position.x = randomNumber(-1.5f,1.5f);
636   position.y = randomNumber(-1.5f,1.5f);
637
638   mDispersionAnimation[ball] = Animation::New(2.0f * mTimeMult);
639   mDispersionAnimation[ball].AnimateTo( Property(mMetaballs[ball].actor, mMetaballs[ball].positionIndex), position);
640   mDispersionAnimation[ball].Play();
641
642   if( ball == METABALL_NUMBER - 1 )
643     mDispersionAnimation[ball].FinishedSignal().Connect( this, &MetaballExplosionController::LaunchResetMetaballPosition );
644 }
645
646 void MetaballExplosionController::LaunchResetMetaballPosition(Animation &source)
647 {
648   for( int i = 0; i < METABALL_NUMBER; i++ )
649   {
650     mDispersionAnimation[i] = Animation::New(1.5f + i*0.25f*mTimeMult);
651     mDispersionAnimation[i].AnimateTo(Property(mMetaballs[i].actor, mMetaballs[i].positionIndex), Vector2(0,0));
652     mDispersionAnimation[i].Play();
653
654     if( i == METABALL_NUMBER - 1 )
655       mDispersionAnimation[i].FinishedSignal().Connect( this, &MetaballExplosionController::EndDisperseAnimation );
656   }
657 }
658
659 void MetaballExplosionController::EndDisperseAnimation(Animation &source)
660 {
661   mCompositionActor.SetProperty( mPositionIndex, Vector2(0,0) );
662 }
663
664 bool MetaballExplosionController::OnTimerDispersionTick()
665 {
666   if( mDispersion < METABALL_NUMBER )
667   {
668     DisperseBallAnimation(mDispersion);
669     mDispersion++;
670   }
671   return true;
672 }
673
674 void MetaballExplosionController::SetPositionToMetaballs(Vector2 & metaballCenter)
675 {
676   //We set the position for the metaballs based on click position
677   for( int i = 0; i < METABALL_NUMBER; i++ )
678   {
679     mMetaballs[i].position = metaballCenter;
680     mMetaballs[i].actor.SetProperty(mMetaballs[i].positionIndex, mMetaballs[i].position);
681   }
682
683   mCompositionActor.SetProperty( mPositionIndex, metaballCenter );
684 }
685
686 bool MetaballExplosionController::OnTouch( Actor actor, const TouchData& touch )
687 {
688   float aspectR = mScreenSize.y / mScreenSize.x;
689
690   switch( touch.GetState( 0 ) )
691   {
692     case PointState::DOWN:
693     {
694       ResetMetaballs(true);
695
696       const Vector2 screen = touch.GetScreenPosition( 0 );
697       Vector2 metaballCenter = Vector2((screen.x / mScreenSize.x) - 0.5, (aspectR * (mScreenSize.y - screen.y) / mScreenSize.y) - 0.5) * 2.0;
698       SetPositionToMetaballs(metaballCenter);
699
700       break;
701     }
702     case PointState::MOTION:
703     {
704       const Vector2 screen = touch.GetScreenPosition( 0 );
705       Vector2 metaballCenter = Vector2((screen.x / mScreenSize.x) - 0.5, (aspectR * (mScreenSize.y - screen.y) / mScreenSize.y) - 0.5) * 2.0;
706       SetPositionToMetaballs(metaballCenter);
707       break;
708     }
709     case PointState::UP:
710     case PointState::LEAVE:
711     case PointState::INTERRUPTED:
712     {
713       mTimerDispersion.Start();
714       break;
715     }
716     default:
717       break;
718     }
719   return true;
720 }
721
722 void MetaballExplosionController::OnKeyEvent(const KeyEvent& event)
723 {
724   if(event.state == KeyEvent::Down)
725   {
726     if( IsKey( event, Dali::DALI_KEY_ESCAPE) || IsKey( event, Dali::DALI_KEY_BACK) )
727     {
728       mApplication.Quit();
729     }
730   }
731 }
732
733
734 //-----------------------------------------------------------------------------------------------
735 //
736 //  Main functions
737 //
738 //-----------------------------------------------------------------------------------------------
739
740 void RunTest( Application& application )
741 {
742   MetaballExplosionController test( application );
743
744   application.MainLoop();
745 }
746
747 // Entry point for Linux & Tizen applications
748 //
749 int DALI_EXPORT_API main( int argc, char **argv )
750 {
751   Application application = Application::New( &argc, &argv );
752
753   RunTest( application );
754
755   return 0;
756 }