Updated demos to use DALi clang-format
[platform/core/uifw/dali-demo.git] / examples / metaball-refrac / metaball-refrac-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/rendering/frame-buffer.h>
24 #include <dali/public-api/rendering/renderer.h>
25 #include <dali/public-api/rendering/texture-set.h>
26 #include <dali/public-api/rendering/texture.h>
27
28 // INTERNAL INCLUDES
29 #include "shared/utility.h" // DemoHelper::LoadTexture
30
31 using namespace Dali;
32
33 namespace // unnamed namespace for constants
34 {
35 const char* const BACKGROUND_IMAGE(DEMO_IMAGE_DIR "background-2.jpg");
36 const float       GRAVITY_X(0);
37 const float       GRAVITY_Y(-0.09);
38
39 // number of metaballs
40 constexpr uint32_t METABALL_NUMBER = 6;
41
42 // clang-format off
43
44 /**
45  * Vertex shader for metaballs
46  */
47 const char* const METABALL_VERTEX_SHADER = DALI_COMPOSE_SHADER (
48     attribute mediump vec2    aPosition;\n
49     attribute mediump vec2    aTexture;\n
50     uniform   mediump mat4    uMvpMatrix;\n
51     uniform   mediump vec3    uSize;\n
52     uniform   lowp    vec4    uColor;\n
53     varying   mediump vec2    vTexCoord;\n
54
55     void main()\n
56     {\n
57       mediump vec4 vertexPosition = vec4(aPosition.x, aPosition.y, 0.0, 1.0);\n
58       vertexPosition = uMvpMatrix * vertexPosition;\n
59       gl_Position = vertexPosition;\n
60       vTexCoord = aTexture;\n
61     }\n
62 );
63
64 /**
65  * Fragment shader for metaballs
66  */
67 const char* const METABALL_FRAG_SHADER = DALI_COMPOSE_SHADER (
68   precision mediump float;\n
69   varying vec2 vTexCoord;\n
70   uniform vec2 uPositionMetaball;\n
71   uniform vec2 uPositionVar;\n
72   uniform vec2 uGravityVector;\n
73   uniform float uRadius;\n
74   uniform float uRadiusVar;\n
75   uniform float uAspect;\n
76   void main()\n
77   {\n
78     vec2 adjustedCoords = vTexCoord * 2.0 - 1.0;\n
79     vec2 finalMetaballPosition = uPositionMetaball + uGravityVector + uPositionVar;\n
80
81     float distance = (adjustedCoords.x - finalMetaballPosition.x) * (adjustedCoords.x - finalMetaballPosition.x) +
82                      (adjustedCoords.y - finalMetaballPosition.y) * (adjustedCoords.y - finalMetaballPosition.y);\n
83     float finalRadius = uRadius + uRadiusVar;\n
84     float color = finalRadius / sqrt( distance );\n
85     vec2 bordercolor = vec2(0.0,0.0);\n
86     if (vTexCoord.x < 0.1)\n
87     {\n
88       bordercolor.x = (0.1 - vTexCoord.x) * 0.8;\n
89     }\n
90     if (vTexCoord.x > 0.9)\n
91     {\n
92       bordercolor.x = (vTexCoord.x - 0.9) * 0.8;\n
93     }\n
94     if (vTexCoord.y < 0.1)\n
95     {\n
96       bordercolor.y = (0.1 - vTexCoord.y) * 0.8;\n
97     }\n
98     if (vTexCoord.y > (0.9 * uAspect))\n
99     {\n
100       bordercolor.y = (vTexCoord.y - (0.9 * uAspect)) * 0.8;\n
101     }\n
102     float border = (bordercolor.x + bordercolor.y) * 0.5;\n
103     gl_FragColor = vec4(color + border,color + border,color + border,1.0);\n
104   }\n
105 );
106
107 /**
108  * Fragment shader code for metaball and background composition with refraction effect
109  */
110 const char* const REFRACTION_FRAG_SHADER = DALI_COMPOSE_SHADER (
111   precision mediump float;\n
112   varying vec2 vTexCoord;\n
113   uniform sampler2D sTexture;\n
114   uniform sampler2D sEffect;\n
115   void main()\n
116   {\n
117     vec4 metaColor = texture2D(sEffect, vTexCoord);\n
118     vec2 zoomCoords;\n
119     float bright = 1.0;\n
120     if (metaColor.r > 0.85)\n
121     {\n
122       zoomCoords = ((vTexCoord - 0.5) * 0.95) + 0.5;\n
123     }\n
124     else if (metaColor.r > 0.78)\n
125     {\n
126       float interpolation = mix(0.95, 1.05, (0.85 - metaColor.r) * 50.0);\n
127       zoomCoords = ((vTexCoord - 0.5) * interpolation) + 0.5;\n
128       bright = 1.2;\n
129     }\n
130     else\n
131     {\n
132       zoomCoords = vTexCoord;\n
133     }\n
134
135     gl_FragColor = texture2D(sTexture, zoomCoords) * bright;\n
136   }\n
137  );
138
139 /**
140  * Fragment shader code when there's no effect
141  */
142 const char* const FRAG_SHADER = DALI_COMPOSE_SHADER (
143   precision mediump float;\n
144   varying vec2 vTexCoord;\n
145   uniform sampler2D sTexture;\n
146   void main()\n
147   {\n
148     gl_FragColor = texture2D(sTexture, vTexCoord);\n
149   }\n
150 );
151 // clang-format on
152
153 /**
154  * Metadata for each ball
155  */
156 struct MetaballInfo
157 {
158   Actor   actor;
159   Vector2 position;
160   float   radius;
161   float   initRadius;
162
163   //Properties needed for animations
164   Property::Index positionIndex;
165   Property::Index positionVarIndex;
166   Property::Index gravityIndex;
167   Property::Index radiusIndex;
168   Property::Index radiusVarIndex;
169   Property::Index aspectIndex;
170 };
171
172 } // unnamed namespace
173
174 /**
175  * Demo using Metaballs
176  *
177  * When the metaball is clicked it starts to grow and fuses into the closest edge of screen
178  */
179 class MetaballRefracController : public ConnectionTracker
180 {
181 public:
182   /**
183    * Constructor
184    * @param application
185    */
186   MetaballRefracController(Application& application);
187
188   /**
189    * Destructor
190    */
191   virtual ~MetaballRefracController();
192
193   /**
194    * Creates the metaballs and initializes the scene
195    */
196   void Create(Application& app);
197
198   /**
199    * Touch handler, start the grow animation and creates additional metaballs
200    */
201   bool OnTouch(Actor actor, const TouchEvent& touch);
202
203   /**
204    * Key event callback to quit the application on escape or back key
205    */
206   void OnKeyEvent(const KeyEvent& event);
207
208 private: // Data
209   Application& mApplication;
210   Vector2      mScreenSize;
211
212   Texture     mBackgroundTexture;
213   FrameBuffer mMetaballFBO;
214
215   Actor        mMetaballRoot;
216   MetaballInfo mMetaballs[METABALL_NUMBER];
217
218   Actor mCompositionActor;
219
220   //Motion
221   Vector2 mCurrentTouchPosition;
222   Vector2 mMetaballPosVariation;
223   Vector2 mMetaballPosVariationFrom;
224   Vector2 mMetaballPosVariationTo;
225   Vector2 mMetaballCenter;
226
227   Vector2 mGravity;
228   Vector2 mGravityVar;
229
230   Renderer   mRendererRefraction;
231   TextureSet mTextureSetRefraction;
232   Shader     mShaderRefraction;
233   TextureSet mTextureSetNormal;
234   Shader     mShaderNormal;
235
236   // Animations
237   Animation mGravityAnimation[METABALL_NUMBER];
238   Animation mRadiusDecAnimation[METABALL_NUMBER];
239   Animation mRadiusIncFastAnimation[METABALL_NUMBER];
240   Animation mRadiusIncSlowAnimation[METABALL_NUMBER];
241   Animation mRadiusVarAnimation[METABALL_NUMBER];
242   Animation mPositionVarAnimation[METABALL_NUMBER];
243
244   // Private Helper functions
245
246   /**
247    * Create a mesh data with the geometry for the metaball rendering
248    * @param aspectMappedTexture whether texture coords should be mapped based on aspect ratio
249    */
250   Geometry CreateGeometry(bool aspectMappedTexture = true);
251
252   /**
253    * Create a actor for the metaballs
254    */
255   void CreateMetaballActors();
256
257   /**
258    * Create the render task and FBO to render the metaballs into a texture
259    */
260   void CreateMetaballImage();
261
262   /**
263    * Create the the final composition
264    */
265   void CreateComposition();
266
267   /**
268    * Create all the metaballs animations (gravity, movement, size, etc.)
269    */
270   void CreateAnimations();
271
272   /**
273    * Function to launch the grow slow radius for the metaballs, and also the small variations for metaball[2] and [3]
274    */
275   void LaunchRadiusIncSlowAnimations(Animation& source);
276
277   /**
278    * Function to launch the animation to get the metaball[1] back to the center
279    */
280   void LaunchGetBackToPositionAnimation(Animation& source);
281
282   /**
283    * Function to stop all animations related to the click of the user in the screen
284    */
285   void StopClickAnimations();
286
287   /**
288    * Function to stop all animations related to the after click of the user in the screen
289    */
290   void StopAfterClickAnimations();
291
292   /**
293    * Function that resets the sate of the different Metaballs
294    */
295   void ResetMetaballsState();
296
297   /**
298    * Function to set the actual position of the metaballs when the user clicks the screen
299    */
300   void SetPositionToMetaballs(const Vector2& metaballCenter);
301 };
302
303 /**
304  * Implementation
305  */
306
307 MetaballRefracController::MetaballRefracController(Application& application)
308 : mApplication(application)
309 {
310   // Connect to the Application's Init signal
311   mApplication.InitSignal().Connect(this, &MetaballRefracController::Create);
312 }
313
314 MetaballRefracController::~MetaballRefracController()
315 {
316   // Nothing to do here;
317 }
318
319 void MetaballRefracController::Create(Application& app)
320 {
321   Window window = app.GetWindow();
322
323   window.KeyEventSignal().Connect(this, &MetaballRefracController::OnKeyEvent);
324
325   mScreenSize = window.GetSize();
326
327   window.SetBackgroundColor(Color::BLACK);
328
329   // Load background texture
330   mBackgroundTexture = DemoHelper::LoadTexture(BACKGROUND_IMAGE);
331
332   mGravity    = Vector2(GRAVITY_X, GRAVITY_Y);
333   mGravityVar = Vector2(0, 0);
334
335   CreateMetaballActors();
336   CreateMetaballImage();
337   CreateComposition();
338   CreateAnimations();
339
340   // Connect the callback to the touch signal on the mesh actor
341   window.GetRootLayer().TouchedSignal().Connect(this, &MetaballRefracController::OnTouch);
342 }
343
344 Geometry MetaballRefracController::CreateGeometry(bool aspectMappedTexture)
345 {
346   const float aspect = mScreenSize.y / mScreenSize.x;
347
348   // Create vertices and specify their color
349   const float xsize = mScreenSize.x * 0.5;
350
351   // Create the meshdata for the metaballs
352   struct VertexPosition
353   {
354     Vector2 position;
355   };
356   struct VertexTexture
357   {
358     Vector2 texture;
359   };
360
361   VertexPosition vertices[] =
362     {
363       {Vector2(-xsize, -xsize * aspect)},
364       {Vector2(xsize, -xsize * aspect)},
365       {Vector2(-xsize, xsize * aspect)},
366       {Vector2(xsize, xsize * aspect)}};
367
368   const float   textureAspect = (aspectMappedTexture) ? aspect : 1.0f;
369   VertexTexture textures[] =
370     {
371       {Vector2(0.0f, 0.0f)},
372       {Vector2(1.0f, 0.0f)},
373       {Vector2(0.0f, 1.0f * textureAspect)},
374       {Vector2(1.0f, 1.0f * textureAspect)}};
375
376   uint32_t numberOfVertices = sizeof(vertices) / sizeof(VertexPosition);
377
378   // Vertices
379   Property::Map positionVertexFormat;
380   positionVertexFormat["aPosition"] = Property::VECTOR2;
381   VertexBuffer positionVertices     = VertexBuffer::New(positionVertexFormat);
382   positionVertices.SetData(vertices, numberOfVertices);
383
384   // Textures
385   Property::Map textureVertexFormat;
386   textureVertexFormat["aTexture"] = Property::VECTOR2;
387   VertexBuffer textureVertices    = VertexBuffer::New(textureVertexFormat);
388   textureVertices.SetData(textures, numberOfVertices);
389
390   // Indices
391   const uint16_t indices[] = {0, 3, 1, 0, 2, 3};
392
393   // Create the geometry object
394   Geometry texturedQuadGeometry = Geometry::New();
395   texturedQuadGeometry.AddVertexBuffer(positionVertices);
396   texturedQuadGeometry.AddVertexBuffer(textureVertices);
397
398   texturedQuadGeometry.SetIndexBuffer(&indices[0], sizeof(indices) / sizeof(indices[0]));
399
400   return texturedQuadGeometry;
401 }
402
403 void MetaballRefracController::CreateMetaballActors()
404 {
405   const float aspect = mScreenSize.y / mScreenSize.x;
406
407   // Create the renderer for the metaballs
408   Shader   shader           = Shader::New(METABALL_VERTEX_SHADER, METABALL_FRAG_SHADER, Shader::Hint::MODIFIES_GEOMETRY);
409   Geometry metaballGeometry = CreateGeometry();
410   Renderer renderer         = Renderer::New(metaballGeometry, shader);
411   renderer.SetProperty(Renderer::Property::BLEND_MODE, BlendMode::ON);
412   renderer.SetProperty(Renderer::Property::BLEND_FACTOR_SRC_RGB, BlendFactor::ONE);
413   renderer.SetProperty(Renderer::Property::BLEND_FACTOR_DEST_RGB, BlendFactor::ONE);
414   renderer.SetProperty(Renderer::Property::BLEND_FACTOR_SRC_ALPHA, BlendFactor::ONE);
415   renderer.SetProperty(Renderer::Property::BLEND_FACTOR_DEST_ALPHA, BlendFactor::ONE);
416
417   // Each metaball has a different radius
418   mMetaballs[0].radius = mMetaballs[0].initRadius = 0.0145f;
419   mMetaballs[1].radius = mMetaballs[1].initRadius = 0.012f;
420   mMetaballs[2].radius = mMetaballs[2].initRadius = 0.0135f;
421   mMetaballs[3].radius = mMetaballs[3].initRadius = 0.0135f;
422
423   // Initialization of each of the metaballs
424   for(uint32_t i = 0; i < METABALL_NUMBER; i++)
425   {
426     mMetaballs[i].position = Vector2(0.0f, 0.0f);
427
428     mMetaballs[i].actor = Actor::New();
429     mMetaballs[i].actor.SetProperty(Dali::Actor::Property::NAME, "Metaball");
430     mMetaballs[i].actor.SetProperty(Actor::Property::SCALE, 1.0f);
431     mMetaballs[i].actor.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
432
433     mMetaballs[i].actor.AddRenderer(renderer);
434
435     mMetaballs[i].positionIndex    = mMetaballs[i].actor.RegisterProperty("uPositionMetaball", mMetaballs[i].position);
436     mMetaballs[i].positionVarIndex = mMetaballs[i].actor.RegisterProperty("uPositionVar", Vector2(0.f, 0.f));
437     mMetaballs[i].gravityIndex     = mMetaballs[i].actor.RegisterProperty("uGravityVector", Vector2(0.f, 0.f));
438     mMetaballs[i].radiusIndex      = mMetaballs[i].actor.RegisterProperty("uRadius", mMetaballs[i].radius);
439     mMetaballs[i].radiusVarIndex   = mMetaballs[i].actor.RegisterProperty("uRadiusVar", 0.f);
440     mMetaballs[i].aspectIndex      = mMetaballs[i].actor.RegisterProperty("uAspect", aspect);
441   }
442
443   //Root creation
444   mMetaballRoot = Actor::New();
445   mMetaballRoot.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
446   for(uint32_t i = 0; i < METABALL_NUMBER; i++)
447   {
448     mMetaballRoot.Add(mMetaballs[i].actor);
449   }
450 }
451
452 void MetaballRefracController::CreateMetaballImage()
453 {
454   // Create an FBO and a render task to create to render the metaballs with a fragment shader
455   Window window = mApplication.GetWindow();
456   mMetaballFBO  = FrameBuffer::New(mScreenSize.x, mScreenSize.y);
457
458   window.Add(mMetaballRoot);
459
460   //Creation of the render task used to render the metaballs
461   RenderTaskList taskList = window.GetRenderTaskList();
462   RenderTask     task     = taskList.CreateTask();
463   task.SetRefreshRate(RenderTask::REFRESH_ALWAYS);
464   task.SetSourceActor(mMetaballRoot);
465   task.SetExclusive(true);
466   task.SetClearColor(Color::BLACK);
467   task.SetClearEnabled(true);
468   task.SetFrameBuffer(mMetaballFBO);
469 }
470
471 void MetaballRefracController::CreateComposition()
472 {
473   // Create Refraction shader and renderer
474   mShaderRefraction = Shader::New(METABALL_VERTEX_SHADER, REFRACTION_FRAG_SHADER);
475
476   // Create new texture set
477   mTextureSetRefraction = TextureSet::New();
478   mTextureSetRefraction.SetTexture(0u, mBackgroundTexture);
479   mTextureSetRefraction.SetTexture(1u, mMetaballFBO.GetColorTexture());
480
481   // Create normal shader
482   mShaderNormal = Shader::New(METABALL_VERTEX_SHADER, FRAG_SHADER);
483
484   // Create new texture set
485   mTextureSetNormal = TextureSet::New();
486   mTextureSetNormal.SetTexture(0u, mBackgroundTexture);
487
488   // Create actor
489   mCompositionActor = Actor::New();
490   mCompositionActor.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
491   mCompositionActor.SetProperty(Actor::Property::POSITION, Vector3(0.0f, 0.0f, 0.0f));
492   mCompositionActor.SetProperty(Actor::Property::SIZE, Vector2(mScreenSize.x, mScreenSize.y));
493
494   // Create geometry
495   Geometry metaballGeometry = CreateGeometry(false);
496   mRendererRefraction       = Renderer::New(metaballGeometry, mShaderNormal);
497   mRendererRefraction.SetTextures(mTextureSetNormal);
498   mCompositionActor.AddRenderer(mRendererRefraction);
499
500   Window window = mApplication.GetWindow();
501   window.Add(mCompositionActor);
502 }
503
504 void MetaballRefracController::CreateAnimations()
505 {
506   uint32_t i = 0;
507   float    key;
508
509   mPositionVarAnimation[1] = Animation::New(2.f);
510   mPositionVarAnimation[1].SetLooping(false);
511   mPositionVarAnimation[1].Pause();
512   mPositionVarAnimation[1].FinishedSignal().Connect(this, &MetaballRefracController::LaunchGetBackToPositionAnimation);
513
514   KeyFrames keySinCosVariation = KeyFrames::New();
515   Vector2   sinCosVariation(0, 0);
516   for(i = 0; i < 360; i++)
517   {
518     sinCosVariation.x = 0.05f * (-sinf(i * Math::PI_OVER_180) + cosf(i * Math::PI_OVER_180));
519     sinCosVariation.y = 0.05f * (sinf(i * Math::PI_OVER_180) - cosf(i * Math::PI_OVER_180));
520     key               = i / 360.f;
521     keySinCosVariation.Add(key, sinCosVariation);
522   }
523
524   mPositionVarAnimation[2] = Animation::New(6.f);
525   mPositionVarAnimation[2].AnimateBetween(Property(mMetaballs[2].actor, mMetaballs[2].positionVarIndex), keySinCosVariation);
526   mPositionVarAnimation[2].SetLooping(true);
527   mPositionVarAnimation[2].Pause();
528
529   KeyFrames keyCosSinVariation = KeyFrames::New();
530   Vector2   cosSinVariation(0, 0);
531   for(i = 0; i < 360; i++)
532   {
533     cosSinVariation.x = 0.05f * (-sinf(i * Math::PI_OVER_180) - cosf(i * Math::PI_OVER_180));
534     cosSinVariation.y = 0.05f * (sinf(i * Math::PI_OVER_180) + cosf(i * Math::PI_OVER_180));
535     key               = i / 360.f;
536     keyCosSinVariation.Add(key, cosSinVariation);
537   }
538
539   mPositionVarAnimation[3] = Animation::New(6.f);
540   mPositionVarAnimation[3].AnimateBetween(Property(mMetaballs[3].actor, mMetaballs[3].positionVarIndex), keyCosSinVariation);
541   mPositionVarAnimation[3].SetLooping(true);
542   mPositionVarAnimation[3].Pause();
543
544   //Animations for gravity
545   for(i = 0; i < METABALL_NUMBER; i++)
546   {
547     mGravityAnimation[i] = Animation::New(25.f);
548     mGravityAnimation[i].AnimateBy(Property(mMetaballs[i].actor, mMetaballs[i].gravityIndex), mGravity * 25.f * 3.f);
549     mGravityAnimation[i].SetLooping(false);
550     mGravityAnimation[i].Pause();
551   }
552
553   //Animation to decrease size of metaballs when there is no click
554   for(i = 0; i < METABALL_NUMBER; i++)
555   {
556     mRadiusDecAnimation[i] = Animation::New(25.f);
557     mRadiusDecAnimation[i].AnimateBy(Property(mMetaballs[i].actor, mMetaballs[i].radiusIndex), -0.004f * 25.f * 3.f);
558     mRadiusDecAnimation[i].SetLooping(false);
559     mRadiusDecAnimation[i].Pause();
560   }
561
562   // Animation to grow the size of the metaballs the first second of the click
563   for(i = 0; i < METABALL_NUMBER; i++)
564   {
565     mRadiusIncFastAnimation[i] = Animation::New(0.3f);
566     mRadiusIncFastAnimation[i].AnimateBy(Property(mMetaballs[i].actor, mMetaballs[i].radiusIndex), 0.06f);
567     mRadiusIncFastAnimation[i].SetLooping(false);
568     mRadiusIncFastAnimation[i].Pause();
569   }
570   mRadiusIncFastAnimation[0].FinishedSignal().Connect(this, &MetaballRefracController::LaunchRadiusIncSlowAnimations);
571
572   // Animation to grow the size of the metaballs afterwards
573   for(i = 0; i < METABALL_NUMBER; i++)
574   {
575     mRadiusIncSlowAnimation[i] = Animation::New(20.f);
576     mRadiusIncSlowAnimation[i].AnimateBy(Property(mMetaballs[i].actor, mMetaballs[i].radiusIndex), 0.04f);
577     mRadiusIncSlowAnimation[i].SetLooping(false);
578     mRadiusIncSlowAnimation[i].Pause();
579   }
580
581   // Keyframes of a sin function
582   KeyFrames keySin = KeyFrames::New();
583   float     val;
584   for(i = 0; i < 360; i++)
585   {
586     val = 0.01f * sin(i * Math::PI / 180.f);
587     key = i / 360.f;
588     keySin.Add(key, val);
589   }
590
591   //Animation to change the size of the metaball
592   mRadiusVarAnimation[2] = Animation::New(8.f);
593   mRadiusVarAnimation[2].AnimateBetween(Property(mMetaballs[2].actor, mMetaballs[2].radiusVarIndex), keySin);
594   mRadiusVarAnimation[2].SetLooping(true);
595
596   // Keyframes of a cos function
597   KeyFrames keyCos = KeyFrames::New();
598   for(i = 0; i < 360; i++)
599   {
600     val = 0.01f * cos(i * Math::PI / 180.f);
601     key = i / 360.f;
602     keyCos.Add(key, val);
603   }
604
605   //Animation to change the size of the metaball
606   mRadiusVarAnimation[3] = Animation::New(8.f);
607   mRadiusVarAnimation[3].AnimateBetween(Property(mMetaballs[3].actor, mMetaballs[3].radiusVarIndex), keyCos);
608   mRadiusVarAnimation[3].SetLooping(true);
609 }
610
611 void MetaballRefracController::LaunchGetBackToPositionAnimation(Animation& source)
612 {
613   mMetaballPosVariationTo = Vector2(0, 0);
614
615   mPositionVarAnimation[1] = Animation::New(1.f);
616   mPositionVarAnimation[1].SetLooping(false);
617   mPositionVarAnimation[1].AnimateTo(Property(mMetaballs[1].actor, mMetaballs[1].positionVarIndex), Vector2(0, 0));
618   mPositionVarAnimation[1].Play();
619 }
620
621 void MetaballRefracController::LaunchRadiusIncSlowAnimations(Animation& source)
622 {
623   for(uint32_t i = 0; i < METABALL_NUMBER; i++)
624   {
625     mRadiusIncSlowAnimation[i].Play();
626   }
627   mPositionVarAnimation[2].Play();
628   mPositionVarAnimation[3].Play();
629 }
630
631 void MetaballRefracController::StopClickAnimations()
632 {
633   for(uint32_t i = 0; i < METABALL_NUMBER; i++)
634   {
635     mRadiusIncSlowAnimation[i].Stop();
636     mRadiusIncFastAnimation[i].Stop();
637   }
638   mPositionVarAnimation[1].Stop();
639   mPositionVarAnimation[2].Stop();
640   mPositionVarAnimation[3].Stop();
641 }
642
643 void MetaballRefracController::StopAfterClickAnimations()
644 {
645   for(uint32_t i = 0; i < METABALL_NUMBER; i++)
646   {
647     mGravityAnimation[i].Stop();
648     mRadiusDecAnimation[i].Stop();
649
650     mMetaballs[i].radius = mMetaballs[i].initRadius;
651
652     mMetaballs[i].actor.SetProperty(mMetaballs[i].gravityIndex, Vector2(0, 0));
653     mMetaballs[i].actor.SetProperty(mMetaballs[i].radiusIndex, mMetaballs[i].radius);
654     mMetaballs[i].actor.SetProperty(mMetaballs[i].radiusVarIndex, 0.f);
655   }
656   mRadiusVarAnimation[2].Stop();
657   mRadiusVarAnimation[3].Stop();
658 }
659
660 void MetaballRefracController::ResetMetaballsState()
661 {
662   mRendererRefraction.SetTextures(mTextureSetNormal);
663   mRendererRefraction.SetShader(mShaderNormal);
664
665   for(uint32_t i = 0; i < METABALL_NUMBER; i++)
666   {
667     mMetaballs[i].radius = mMetaballs[i].initRadius;
668   }
669
670   mMetaballPosVariationTo   = Vector2(0, 0);
671   mMetaballPosVariationFrom = Vector2(0, 0);
672   mMetaballPosVariation     = Vector2(0, 0);
673   mGravityVar               = Vector2(0, 0);
674 }
675
676 void MetaballRefracController::SetPositionToMetaballs(const Vector2& metaballCenter)
677 {
678   //We set the position for the metaballs based on click position
679   for(uint32_t i = 0; i < METABALL_NUMBER; i++)
680   {
681     mMetaballs[i].position = metaballCenter;
682     mMetaballs[i].actor.SetProperty(mMetaballs[i].positionIndex, mMetaballs[i].position);
683   }
684 }
685
686 bool MetaballRefracController::OnTouch(Actor actor, const TouchEvent& touch)
687 {
688   const float aspect = mScreenSize.y / mScreenSize.x;
689   switch(touch.GetState(0))
690   {
691     case PointState::DOWN:
692     {
693       StopAfterClickAnimations();
694       for(uint32_t i = 0; i < METABALL_NUMBER; i++)
695       {
696         mRadiusIncFastAnimation[i].Play();
697       }
698       mRadiusVarAnimation[2].Play();
699       mRadiusVarAnimation[3].Play();
700
701       //We draw with the refraction-composition shader
702       mRendererRefraction.SetTextures(mTextureSetRefraction);
703       mRendererRefraction.SetShader(mShaderRefraction);
704       mCurrentTouchPosition = touch.GetScreenPosition(0);
705
706       //we use the click position for the metaballs
707       Vector2 metaballCenter = Vector2((mCurrentTouchPosition.x / mScreenSize.x) - 0.5f,
708                                        (aspect * (mScreenSize.y - mCurrentTouchPosition.y) / mScreenSize.y) - 0.5f) *
709                                2.0f;
710       SetPositionToMetaballs(metaballCenter);
711       break;
712     }
713     case PointState::MOTION:
714     {
715       Vector2 screen        = touch.GetScreenPosition(0);
716       Vector2 displacement  = screen - mCurrentTouchPosition;
717       mCurrentTouchPosition = screen;
718
719       mMetaballPosVariationTo.x += (displacement.x / mScreenSize.x) * 2.2f;
720       mMetaballPosVariationTo.y += (-displacement.y / mScreenSize.y) * 2.2f;
721
722       if(mPositionVarAnimation[1])
723       {
724         mPositionVarAnimation[1].FinishedSignal().Disconnect(this, &MetaballRefracController::LaunchGetBackToPositionAnimation);
725         mPositionVarAnimation[1].Stop();
726       }
727       mPositionVarAnimation[1] = Animation::New(1.f);
728       mPositionVarAnimation[1].SetLooping(false);
729       mPositionVarAnimation[1].AnimateTo(Property(mMetaballs[1].actor, mMetaballs[1].positionVarIndex), mMetaballPosVariationTo);
730       mPositionVarAnimation[1].FinishedSignal().Connect(this, &MetaballRefracController::LaunchGetBackToPositionAnimation);
731       mPositionVarAnimation[1].Play();
732
733       //we use the click position for the metaballs
734       Vector2 metaballCenter = Vector2((screen.x / mScreenSize.x) - 0.5f,
735                                        (aspect * (mScreenSize.y - screen.y) / mScreenSize.y) - 0.5f) *
736                                2.0f;
737       SetPositionToMetaballs(metaballCenter);
738       break;
739     }
740     case PointState::UP:
741     case PointState::LEAVE:
742     case PointState::INTERRUPTED:
743     {
744       //Stop click animations
745       StopClickAnimations();
746
747       //Launch out of screen animations
748       for(uint32_t i = 0; i < METABALL_NUMBER; i++)
749       {
750         mGravityAnimation[i].Play();
751       }
752
753       for(uint32_t i = 0; i < METABALL_NUMBER; i++)
754       {
755         mRadiusDecAnimation[i].Play();
756       }
757       break;
758     }
759     default:
760       break;
761   }
762   return true;
763 }
764
765 void MetaballRefracController::OnKeyEvent(const KeyEvent& event)
766 {
767   if(event.GetState() == KeyEvent::DOWN)
768   {
769     if(IsKey(event, Dali::DALI_KEY_ESCAPE) || IsKey(event, Dali::DALI_KEY_BACK))
770     {
771       mApplication.Quit();
772     }
773   }
774 }
775
776 /**
777  * Main entry point
778  */
779 int32_t DALI_EXPORT_API main(int argc, char** argv)
780 {
781   Application application = Application::New(&argc, &argv);
782
783   MetaballRefracController test(application);
784   application.MainLoop();
785
786   return 0;
787 }