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