Resurrected Metaball effects
[platform/core/uifw/dali-demo.git] / examples / metaball-explosion / metaball-explosion-example.cpp
1 /*
2  * Copyright (c) 2018 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 <cstdint> // uint32_t, uint16_t etc
22
23 #include <dali/public-api/rendering/renderer.h>
24 #include <dali/public-api/rendering/texture.h>
25 #include <dali/public-api/rendering/texture-set.h>
26 #include <dali/public-api/rendering/frame-buffer.h>
27 #include <dali/public-api/math/random.h>
28
29 // INTERNAL INCLUDES
30 #include "shared/utility.h" // DemoHelper::LoadTexture
31
32 using namespace Dali;
33
34 namespace // unnamed namespace for constants
35 {
36 // background image
37 const char * const BACKGROUND_IMAGE( DEMO_IMAGE_DIR "background-2.jpg" );
38
39 // number of metaballs
40 constexpr uint32_t METABALL_NUMBER = 6;
41
42 /**
43  * Vertex shader code for metaball
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  * Fragment shader code for metaball
63  */
64 const char* const METABALL_FRAG_SHADER = DALI_COMPOSE_SHADER (
65   precision mediump float;\n
66   varying vec2 vTexCoord;\n
67   uniform vec2 uPositionMetaball;\n
68   uniform vec2 uPositionVar;\n
69   uniform vec2 uGravityVector;\n
70   uniform float uRadius;\n
71   uniform float uRadiusVar;\n
72   void main()\n
73   {\n
74     vec2 adjustedCoords = vTexCoord * 2.0 - 1.0;\n
75     vec2 finalMetaballPosition = uPositionMetaball + uGravityVector + uPositionVar;\n
76     \n
77     float finalRadius = uRadius + uRadiusVar;\n
78     vec2 distanceVec = adjustedCoords - finalMetaballPosition;\n
79     float result = dot(distanceVec, distanceVec);\n
80     float color = inversesqrt(result) * finalRadius;\n
81     \n
82     gl_FragColor = vec4(color,color,color,1.0);\n
83   }\n
84 );
85
86 /**
87  * Fragment shader code for metaball and background composition with refraction effect
88  */
89 const char* const REFRACTION_FRAG_SHADER = DALI_COMPOSE_SHADER (
90   precision highp float;\n
91   varying vec2 vTexCoord;\n
92   uniform sampler2D sTexture;\n
93   uniform sampler2D sEffect;\n
94   uniform vec2 uPositionMetaball;\n
95   void main()\n
96   {\n
97     vec2 zoomCoords;\n
98     vec3 normal = vec3(0.0,0.0,1.0);\n
99     vec2 fakePos = vec2(0.0,0.0);\n
100     vec3 color = vec3(1.0, 1.0, 1.0);
101     float ambient = 0.2;
102     \n
103     vec4 metaColor = texture2D(sEffect, vTexCoord);\n
104     \n
105     vec2 adjustedCoords = vTexCoord.xy * vec2(2.0) - vec2(1.0);\n
106     fakePos = adjustedCoords.xy - vec2(uPositionMetaball.x, -uPositionMetaball.y);
107     float len = length(fakePos) + 0.01;\n
108     vec3 colorPos = vec3(0,0,1);
109     \n
110     if (metaColor.r > 0.85)\n
111     {\n
112       zoomCoords = ((vTexCoord - 0.5) * 0.9);\n
113       zoomCoords = zoomCoords + 0.5;\n
114       \n
115       float interpNormal = mix(0.7, 1.0, (metaColor.r - 0.85) * 4.);\n
116       normal.xyz = vec3(fakePos.x * (1.0 - interpNormal) / len, fakePos.y * (1.0 - interpNormal) / len, interpNormal);\n
117       normal.xyz = normalize(normal.xyz);\n
118       color = vec3(0.65, 1.0, 0);\n
119       colorPos = vec3(fakePos.x,fakePos.y,0);
120     }\n
121     else if (metaColor.r > 0.75)\n
122     {\n
123       float interpolation = mix(0.9, 1.15, (0.85 - metaColor.r) * 10.0);\n
124       zoomCoords = ((vTexCoord - 0.5) * interpolation);\n
125       zoomCoords = zoomCoords + 0.5;\n
126       \n
127       float interpNormal = mix(0.7, 0.0, (0.85 - metaColor.r) * 10.0);\n
128       normal.xyz = vec3(fakePos.x * (1.0 - interpNormal) / len, fakePos.y * (1.0 - interpNormal) / len, interpNormal);\n
129       normal.xyz = normalize(normal.xyz);\n
130       color = vec3(0.65, 1.0, 0);\n
131       colorPos = vec3(fakePos.x,fakePos.y,0);
132     }\n
133     else\n
134     {\n
135       zoomCoords = vTexCoord;\n
136       normal = vec3(0,0,0);\n
137       ambient = 0.5;\n
138     }\n
139     \n
140     vec3 lightPosition = vec3(-750.0,-1000.0,2000.0);\n
141     vec3 vertex = vec3(adjustedCoords.x,adjustedCoords.y,0.0);\n
142     \n
143     vec3 vecToLight = normalize( lightPosition - vertex );\n
144     \n
145     float lightDiffuse = dot( vecToLight, normal );\n
146     lightDiffuse = max(0.0,lightDiffuse);\n
147     lightDiffuse = lightDiffuse * 0.5 + 0.5;
148     \n
149     vec3 vertexToEye = vec3(0,0,1) - vertex;\n
150     vertexToEye = normalize(vertexToEye);
151     vec3 lightReflect = normalize(reflect(-vecToLight, normal));\n
152     float specularFactor = max(0.0,dot(vertexToEye, lightReflect));\n
153     specularFactor = pow(specularFactor, 32.0) * 0.7;
154     \n
155     vec4 texColor = texture2D(sTexture, zoomCoords);\n
156     gl_FragColor.rgb = texColor.rgb * ambient + color.rgb * texColor.rgb * lightDiffuse + vec3(specularFactor);\n
157     gl_FragColor.a = 1.0;
158   }\n
159  );
160
161 /**
162  * Metadata for each ball
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 } // unnamed namespace
177
178 /**
179  * Demo using Metaballs
180  *
181  * When the metaball is clicked it explodes to smaller balls
182  */
183 class MetaballExplosionController : public ConnectionTracker
184 {
185 public:
186
187   /**
188    * Constructor
189    * @param application
190    */
191   MetaballExplosionController( Application& application );
192
193   /**
194    * Destructor
195    */
196   virtual ~MetaballExplosionController();
197
198   /**
199    * Creates the metaballs and initializes the scene
200    */
201   void Create( Application& app );
202
203   /**
204    * Touch event handler to center metaballs at touch position
205    * and start explosion animation on release
206    */
207   bool OnTouch( Actor actor, const TouchData& touch );
208
209   /**
210    * Key event handler to quit application on escape or back key
211    */
212   void OnKeyEvent(const KeyEvent& event);
213
214 private: // Data
215
216   Application&      mApplication;
217   Vector2           mScreenSize;
218
219   Texture           mBackgroundTexture;
220   FrameBuffer       mMetaballFBO;
221   Texture           mMetaballFBOTexture;
222
223   Actor             mMetaballRoot;
224   MetaballInfo      mMetaballs[METABALL_NUMBER];
225
226   Property::Index   mPositionIndex;
227   Actor             mCompositionActor;
228
229   //Motion
230   Vector2           mCurrentTouchPosition;
231   Vector2           mMetaballPosVariation;
232   Vector2           mMetaballPosVariationFrom;
233   Vector2           mMetaballPosVariationTo;
234   Vector2           mMetaballCenter;
235
236   //Animations
237   Animation         mPositionVarAnimation[METABALL_NUMBER];
238
239   uint32_t          mDispersion;
240   Animation         mDispersionAnimation[METABALL_NUMBER];
241
242   Timer             mTimerDispersion;
243
244   float             mTimeMultiplier;
245
246   // Private helper functions
247
248   /**
249    * Create a mesh data with the geometry for the metaball rendering
250    * @param aspectMappedTexture whether texture coords should be mapped based on aspect ratio
251    */
252   Geometry CreateGeometry( bool aspectMappedTexture = true );
253
254   /**
255    * Create a actors and renderers for the metaballs
256    */
257   void CreateMetaballActors();
258
259   /**
260    * Create the render task and FBO to render the metaballs into a texture
261    */
262   void CreateMetaballImage();
263
264   /**
265    * Create the the final composition
266    */
267   void CreateComposition();
268
269   /**
270    * Function to create animations for the small variations of position inside the metaball
271    */
272   void CreateAnimations();
273
274   /**
275    * Function to reset metaball state
276    */
277   void ResetMetaballs( bool resetAnims );
278
279   /**
280    * Function to create disperse each of the ball that compose the metaball when exploding
281    */
282   void DisperseBallAnimation( uint32_t ball );
283
284   /**
285    * Function to make metaballs come back to reset position
286    */
287   void LaunchResetMetaballPosition( Animation& source );
288
289   /**
290    * Function to set things at the end of the animation
291    */
292   void EndDisperseAnimation( Animation& source );
293
294   /**
295    * Function to init dispersion of the metaballs one by one using a timer
296    * (so not all the balls begin moving at the same time)
297    */
298   bool OnTimerDispersionTick();
299
300   /**
301    * Function to set the actual position of the metaballs when the user clicks the screen
302    */
303   void SetPositionToMetaballs( const Vector2& metaballCenter );
304 };
305
306 /**
307  * Implementation
308  */
309
310 MetaballExplosionController::MetaballExplosionController( Application& application )
311 : mApplication( application ),
312   mScreenSize(),
313   mBackgroundTexture(),
314   mMetaballFBO(),
315   mMetaballFBOTexture(),
316   mMetaballRoot(),
317   mMetaballs(),
318   mPositionIndex(),
319   mCompositionActor(),
320   mCurrentTouchPosition(),
321   mMetaballPosVariation(),
322   mMetaballPosVariationFrom(),
323   mMetaballPosVariationTo(),
324   mMetaballCenter(),
325   mPositionVarAnimation(),
326   mDispersion( 0 ),
327   mDispersionAnimation(),
328   mTimerDispersion(),
329   mTimeMultiplier( 1.0f )
330 {
331   // Connect to the Application's Init signal
332   mApplication.InitSignal().Connect( this, &MetaballExplosionController::Create );
333 }
334
335 MetaballExplosionController::~MetaballExplosionController()
336 {
337   // Nothing to do here;
338 }
339
340 void MetaballExplosionController::Create( Application& app )
341 {
342   Stage stage = Stage::GetCurrent();
343
344   stage.KeyEventSignal().Connect( this, &MetaballExplosionController::OnKeyEvent );
345
346   mScreenSize = stage.GetSize();
347
348   mTimeMultiplier = 1.0f;
349
350   stage.SetBackgroundColor(Color::BLACK);
351
352   // Load background texture
353   mBackgroundTexture = DemoHelper::LoadTexture( BACKGROUND_IMAGE );
354
355   srand( static_cast<uint32_t>( time(0) ) );
356
357   //Create internal data
358   CreateMetaballActors();
359   CreateMetaballImage();
360   CreateComposition();
361
362   CreateAnimations();
363
364   mDispersion = 0;
365   mTimerDispersion = Timer::New( 150 );
366   mTimerDispersion.TickSignal().Connect( this, &MetaballExplosionController::OnTimerDispersionTick );
367
368   // Connect the callback to the touch signal on the mesh actor
369   stage.GetRootLayer().TouchSignal().Connect( this, &MetaballExplosionController::OnTouch );
370 }
371
372 Geometry MetaballExplosionController::CreateGeometry( bool aspectMappedTexture )
373 {
374   const float aspect = mScreenSize.y / mScreenSize.x;
375
376   // Create vertices and specify their color
377   const float xsize = mScreenSize.x * 0.5;
378
379   // Create the meshdata for the metaballs
380   struct VertexPosition { Vector2 position; };
381   struct VertexTexture { Vector2 texture; };
382
383   VertexPosition vertices[] =
384   {
385     { Vector2( -xsize, -xsize * aspect ) },
386     { Vector2(  xsize, -xsize * aspect ) },
387     { Vector2( -xsize,  xsize * aspect ) },
388     { Vector2(  xsize,  xsize * aspect ) }
389   };
390
391   const float textureAspect = (aspectMappedTexture) ? aspect : 1.0f;
392   VertexTexture textures[] =
393   {
394     { Vector2( 0.0f, 0.0f ) },
395     { Vector2( 1.0f, 0.0f ) },
396     { Vector2( 0.0f, 1.0f * textureAspect ) },
397     { Vector2( 1.0f, 1.0f * textureAspect ) }
398   };
399
400   uint32_t numberOfVertices = sizeof(vertices)/sizeof(VertexPosition);
401
402   // Vertices
403   Property::Map positionVertexFormat;
404   positionVertexFormat["aPosition"] = Property::VECTOR2;
405   PropertyBuffer positionVertices = PropertyBuffer::New( positionVertexFormat );
406   positionVertices.SetData( vertices, numberOfVertices );
407
408   // Textures
409   Property::Map textureVertexFormat;
410   textureVertexFormat["aTexture"] = Property::VECTOR2;
411   PropertyBuffer textureVertices = PropertyBuffer::New( textureVertexFormat );
412   textureVertices.SetData( textures, numberOfVertices );
413
414   // Indices
415   const uint16_t indices[] = { 0, 3, 1, 0, 2, 3 };
416
417   // Create the geometry object
418   Geometry texturedQuadGeometry = Geometry::New();
419   texturedQuadGeometry.AddVertexBuffer( positionVertices );
420   texturedQuadGeometry.AddVertexBuffer( textureVertices );
421
422   texturedQuadGeometry.SetIndexBuffer ( &indices[0], sizeof( indices )/ sizeof( indices[0] ) );
423
424   return texturedQuadGeometry;
425 }
426
427 void MetaballExplosionController::CreateMetaballActors()
428 {
429   // Create the shader for the metaballs, tell DALi that shader modifies geometry so we dont need to set a meaningless size
430   Shader shader = Shader::New( METABALL_VERTEX_SHADER, METABALL_FRAG_SHADER, Shader::Hint::MODIFIES_GEOMETRY );
431
432   Geometry metaballGeom = CreateGeometry();
433   // Reuse same renderer for each actor
434   Renderer renderer = Renderer::New( metaballGeom, shader );
435   renderer.SetProperty( Renderer::Property::BLEND_MODE, BlendMode::ON );
436   renderer.SetProperty( Renderer::Property::BLEND_FACTOR_SRC_RGB,    BlendFactor::ONE );
437   renderer.SetProperty( Renderer::Property::BLEND_FACTOR_DEST_RGB,   BlendFactor::ONE );
438   renderer.SetProperty( Renderer::Property::BLEND_FACTOR_SRC_ALPHA,  BlendFactor::ONE );
439   renderer.SetProperty( Renderer::Property::BLEND_FACTOR_DEST_ALPHA, BlendFactor::ONE  );
440
441   //Initialization of each of the metaballs
442   for( uint32_t i = 0; i < METABALL_NUMBER; i++ )
443   {
444     mMetaballs[i].position = Vector2(0.0f, 0.0f);
445     mMetaballs[i].radius = mMetaballs[i].initRadius = Random::Range(0.05f,0.07f);
446
447     mMetaballs[i].actor = Actor::New( );
448     mMetaballs[i].actor.SetName( "Metaball" );
449     mMetaballs[i].actor.SetScale( 1.0f );
450     mMetaballs[i].actor.SetParentOrigin( ParentOrigin::CENTER );
451     mMetaballs[i].actor.AddRenderer( renderer );
452
453     mMetaballs[i].positionIndex = mMetaballs[i].actor.RegisterProperty( "uPositionMetaball", mMetaballs[i].position );
454
455     mMetaballs[i].positionVarIndex = mMetaballs[i].actor.RegisterProperty( "uPositionVar", Vector2(0.f,0.f) );
456
457     mMetaballs[i].actor.RegisterProperty( "uGravityVector", Vector2(Random::Range(-0.2,0.2),Random::Range(-0.2,0.2)) );
458     mMetaballs[i].actor.RegisterProperty( "uRadius", mMetaballs[i].radius );
459     mMetaballs[i].actor.RegisterProperty( "uRadiusVar", 0.f );
460   }
461
462   // Root creation
463   mMetaballRoot = Actor::New();
464   mMetaballRoot.SetParentOrigin( ParentOrigin::CENTER );
465   for( uint32_t i = 0; i < METABALL_NUMBER; i++ )
466   {
467     mMetaballRoot.Add( mMetaballs[i].actor );
468   }
469
470 }
471
472 void MetaballExplosionController::CreateMetaballImage()
473 {
474   // Create an FBO and a render task to create to render the metaballs with a fragment shader
475   Stage stage = Stage::GetCurrent();
476
477   mMetaballFBO = FrameBuffer::New( mScreenSize.x, mScreenSize.y, FrameBuffer::Attachment::NONE );
478   mMetaballFBOTexture = Texture::New( Dali::TextureType::TEXTURE_2D,
479                                       Pixel::RGB888,
480                                       mScreenSize.x, mScreenSize.y );
481   mMetaballFBO.AttachColorTexture( mMetaballFBOTexture );
482
483   stage.Add(mMetaballRoot);
484
485   // Create the render task used to render the metaballs
486   RenderTaskList taskList = Stage::GetCurrent().GetRenderTaskList();
487   RenderTask task = taskList.CreateTask();
488   task.SetRefreshRate( RenderTask::REFRESH_ALWAYS );
489   task.SetSourceActor( mMetaballRoot );
490   task.SetExclusive( true );
491   task.SetClearColor( Color::BLACK );
492   task.SetClearEnabled( true );
493   task.SetFrameBuffer( mMetaballFBO );
494 }
495
496 void MetaballExplosionController::CreateComposition()
497 {
498   //Create new shader
499   Shader shader = Shader::New( METABALL_VERTEX_SHADER, REFRACTION_FRAG_SHADER );
500
501   // Create new texture set
502   auto textureSet = TextureSet::New();
503   textureSet.SetTexture( 0u, mBackgroundTexture  );
504   textureSet.SetTexture( 1u, mMetaballFBOTexture );
505
506   // Create geometry
507   Geometry metaballGeom = CreateGeometry( false );
508
509   Renderer mRenderer = Renderer::New( metaballGeom, shader );
510   mRenderer.SetTextures( textureSet );
511
512   // Create actor
513   mCompositionActor = Actor::New( );
514   mCompositionActor.SetParentOrigin(ParentOrigin::CENTER);
515   mCompositionActor.SetPosition(Vector3(0.0f, 0.0f, 0.0f));
516   mCompositionActor.SetSize(mScreenSize.x, mScreenSize.y);
517   mCompositionActor.AddRenderer( mRenderer );
518
519   Vector2 metaballCenter(0.0,0);
520   metaballCenter.x = metaballCenter.x * 0.5;
521   metaballCenter.y = metaballCenter.y * 0.5;
522   mPositionIndex = mCompositionActor.RegisterProperty( "uPositionMetaball", metaballCenter );
523
524   SetPositionToMetaballs( metaballCenter );
525
526   mCompositionActor.SetSize(mScreenSize.x, mScreenSize.y);
527
528   Stage stage = Stage::GetCurrent();
529   stage.Add( mCompositionActor );
530 }
531
532 void MetaballExplosionController::CreateAnimations()
533 {
534   Vector2 direction;
535
536   for( uint32_t i = 0; i < METABALL_NUMBER; i++ )
537   {
538     KeyFrames keySinCosVariation = KeyFrames::New();
539     Vector2 sinCosVariation( 0,0 );
540
541     direction.x = Random::Range( -100.f,100.f );
542     direction.y = Random::Range( -100.f,100.f );
543
544     direction.Normalize();
545     direction *= 0.1f;
546
547     for( uint32_t j = 0; j < 360; j++ )
548     {
549       sinCosVariation.x = sinf( j * Math::PI/180.f ) * direction.x;
550       sinCosVariation.y = cosf( j * Math::PI/180.f ) * direction.y;
551       float key = j/360.f;
552       keySinCosVariation.Add( key, sinCosVariation );
553     }
554
555     mPositionVarAnimation[i] = Animation::New( 3.f );
556     mPositionVarAnimation[i].AnimateBetween( Property( mMetaballs[i].actor, mMetaballs[i].positionVarIndex ), keySinCosVariation );
557     mPositionVarAnimation[i].SetLooping( true );
558     mPositionVarAnimation[i].Play();
559   }
560 }
561
562 void MetaballExplosionController::ResetMetaballs( bool resetAnims )
563 {
564   for( uint32_t i = 0; i < METABALL_NUMBER; i++ )
565   {
566     if( mDispersionAnimation[i] )
567     {
568       mDispersionAnimation[i].Clear();
569     }
570
571     mMetaballs[i].position = Vector2( 0.0f, 0.0f );
572     mMetaballs[i].actor.SetProperty( mMetaballs[i].positionIndex, mMetaballs[i].position );
573   }
574   mTimerDispersion.Stop();
575   mDispersion = 0;
576
577   mCompositionActor.SetProperty( mPositionIndex, Vector2(0,0) );
578 }
579
580 void MetaballExplosionController::DisperseBallAnimation( uint32_t ball )
581 {
582   Vector2 position;
583   position.x = Random::Range(-1.5f,1.5f);
584   position.y = Random::Range(-1.5f,1.5f);
585
586   mDispersionAnimation[ball] = Animation::New(2.0f * mTimeMultiplier);
587   mDispersionAnimation[ball].AnimateTo( Property(mMetaballs[ball].actor, mMetaballs[ball].positionIndex), position);
588   mDispersionAnimation[ball].Play();
589
590   if( ball == METABALL_NUMBER - 1 )
591   {
592     mDispersionAnimation[ball].FinishedSignal().Connect( this, &MetaballExplosionController::LaunchResetMetaballPosition );
593   }
594 }
595
596 void MetaballExplosionController::LaunchResetMetaballPosition( Animation& source )
597 {
598   for( uint32_t i = 0; i < METABALL_NUMBER; i++ )
599   {
600     mDispersionAnimation[i] = Animation::New( 1.5f + i * 0.25f * mTimeMultiplier );
601     mDispersionAnimation[i].AnimateTo(Property( mMetaballs[i].actor, mMetaballs[i].positionIndex), Vector2(0,0) );
602     mDispersionAnimation[i].Play();
603
604     if( i == METABALL_NUMBER - 1 )
605     {
606       mDispersionAnimation[i].FinishedSignal().Connect( this, &MetaballExplosionController::EndDisperseAnimation );
607     }
608   }
609 }
610
611 void MetaballExplosionController::EndDisperseAnimation( Animation& source )
612 {
613   mCompositionActor.SetProperty( mPositionIndex, Vector2(0,0) );
614 }
615
616 bool MetaballExplosionController::OnTimerDispersionTick()
617 {
618   if( mDispersion < METABALL_NUMBER )
619   {
620     DisperseBallAnimation( mDispersion );
621     mDispersion++;
622   }
623   return true;
624 }
625
626 void MetaballExplosionController::SetPositionToMetaballs( const Vector2& metaballCenter )
627 {
628   //We set the position for the metaballs based on click position
629   for( uint32_t i = 0; i < METABALL_NUMBER; i++ )
630   {
631     mMetaballs[i].position = metaballCenter;
632     mMetaballs[i].actor.SetProperty( mMetaballs[i].positionIndex, mMetaballs[i].position );
633   }
634
635   mCompositionActor.SetProperty( mPositionIndex, metaballCenter );
636 }
637
638 bool MetaballExplosionController::OnTouch( Actor actor, const TouchData& touch )
639 {
640   float aspectR = mScreenSize.y / mScreenSize.x;
641
642   switch( touch.GetState( 0 ) )
643   {
644     case PointState::DOWN:
645     {
646       ResetMetaballs(true);
647
648       const Vector2 screen = touch.GetScreenPosition( 0 );
649       Vector2 metaballCenter = Vector2( (screen.x / mScreenSize.x) - 0.5f, (aspectR * (mScreenSize.y - screen.y) / mScreenSize.y) - 0.5f ) * 2.0f;
650       SetPositionToMetaballs(metaballCenter);
651
652       break;
653     }
654     case PointState::MOTION:
655     {
656       const Vector2 screen = touch.GetScreenPosition( 0 );
657       Vector2 metaballCenter = Vector2( (screen.x / mScreenSize.x) - 0.5f, (aspectR * (mScreenSize.y - screen.y) / mScreenSize.y) - 0.5f ) * 2.0f;
658       SetPositionToMetaballs(metaballCenter);
659       break;
660     }
661     case PointState::UP:
662     case PointState::LEAVE:
663     case PointState::INTERRUPTED:
664     {
665       mTimerDispersion.Start();
666       break;
667     }
668     default:
669       break;
670     }
671   return true;
672 }
673
674 void MetaballExplosionController::OnKeyEvent(const KeyEvent& event)
675 {
676   if(event.state == KeyEvent::Down)
677   {
678     if( IsKey( event, Dali::DALI_KEY_ESCAPE) || IsKey( event, Dali::DALI_KEY_BACK) )
679     {
680       mApplication.Quit();
681     }
682   }
683 }
684
685 /**
686  * Main entry point
687  */
688 int32_t DALI_EXPORT_API main( int argc, char **argv )
689 {
690   Application application = Application::New( &argc, &argv );
691
692   MetaballExplosionController test( application );
693
694   application.MainLoop();
695
696   return 0;
697 }