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