[dali_1.3.52] Merge branch 'devel/master'
[platform/core/uifw/dali-demo.git] / examples / metaball-refrac / metaball-refrac-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
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 TouchData& 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   Texture           mMetaballFBOTexture;
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 /**
305  * Implementation
306  */
307
308 MetaballRefracController::MetaballRefracController( Application& application )
309   : mApplication( application )
310 {
311   // Connect to the Application's Init signal
312   mApplication.InitSignal().Connect( this, &MetaballRefracController::Create );
313 }
314
315 MetaballRefracController::~MetaballRefracController()
316 {
317   // Nothing to do here;
318 }
319
320 void MetaballRefracController::Create( Application& app )
321 {
322   Stage stage = Stage::GetCurrent();
323
324   stage.KeyEventSignal().Connect( this, &MetaballRefracController::OnKeyEvent );
325
326   mScreenSize = stage.GetSize();
327
328   stage.SetBackgroundColor(Color::BLACK);
329
330   // Load background texture
331   mBackgroundTexture = DemoHelper::LoadTexture( BACKGROUND_IMAGE );
332
333   mGravity = Vector2(GRAVITY_X,GRAVITY_Y);
334   mGravityVar = Vector2(0,0);
335
336   CreateMetaballActors();
337   CreateMetaballImage();
338   CreateComposition();
339   CreateAnimations();
340
341   // Connect the callback to the touch signal on the mesh actor
342   stage.GetRootLayer().TouchSignal().Connect( this, &MetaballRefracController::OnTouch );
343 }
344
345 Geometry MetaballRefracController::CreateGeometry( bool aspectMappedTexture )
346 {
347   const float aspect = mScreenSize.y / mScreenSize.x;
348
349   // Create vertices and specify their color
350   const float xsize = mScreenSize.x * 0.5;
351
352   // Create the meshdata for the metaballs
353   struct VertexPosition { Vector2 position; };
354   struct VertexTexture { Vector2 texture; };
355
356   VertexPosition vertices[] =
357   {
358     { Vector2( -xsize, -xsize * aspect ) },
359     { Vector2(  xsize, -xsize * aspect ) },
360     { Vector2( -xsize,  xsize * aspect ) },
361     { Vector2(  xsize,  xsize * aspect ) }
362   };
363
364   const float textureAspect = (aspectMappedTexture) ? aspect : 1.0f;
365   VertexTexture textures[] =
366   {
367     { Vector2( 0.0f, 0.0f ) },
368     { Vector2( 1.0f, 0.0f ) },
369     { Vector2( 0.0f, 1.0f * textureAspect ) },
370     { Vector2( 1.0f, 1.0f * textureAspect ) }
371   };
372
373   uint32_t numberOfVertices = sizeof(vertices)/sizeof(VertexPosition);
374
375   // Vertices
376   Property::Map positionVertexFormat;
377   positionVertexFormat["aPosition"] = Property::VECTOR2;
378   PropertyBuffer positionVertices = PropertyBuffer::New( positionVertexFormat );
379   positionVertices.SetData( vertices, numberOfVertices );
380
381   // Textures
382   Property::Map textureVertexFormat;
383   textureVertexFormat["aTexture"] = Property::VECTOR2;
384   PropertyBuffer textureVertices = PropertyBuffer::New( textureVertexFormat );
385   textureVertices.SetData( textures, numberOfVertices );
386
387   // Indices
388   const uint16_t indices[] = { 0, 3, 1, 0, 2, 3 };
389
390   // Create the geometry object
391   Geometry texturedQuadGeometry = Geometry::New();
392   texturedQuadGeometry.AddVertexBuffer( positionVertices );
393   texturedQuadGeometry.AddVertexBuffer( textureVertices );
394
395   texturedQuadGeometry.SetIndexBuffer ( &indices[0], sizeof( indices )/ sizeof( indices[0] ) );
396
397   return texturedQuadGeometry;
398 }
399
400 void MetaballRefracController::CreateMetaballActors()
401 {
402   const float aspect = mScreenSize.y / mScreenSize.x;
403
404   // Create the renderer for the metaballs
405   Shader shader = Shader::New( METABALL_VERTEX_SHADER, METABALL_FRAG_SHADER, Shader::Hint::MODIFIES_GEOMETRY );
406   Geometry metaballGeometry = CreateGeometry();
407   Renderer renderer = Renderer::New( metaballGeometry, shader );
408   renderer.SetProperty( Renderer::Property::BLEND_MODE, BlendMode::ON );
409   renderer.SetProperty( Renderer::Property::BLEND_FACTOR_SRC_RGB,    BlendFactor::ONE );
410   renderer.SetProperty( Renderer::Property::BLEND_FACTOR_DEST_RGB,   BlendFactor::ONE );
411   renderer.SetProperty( Renderer::Property::BLEND_FACTOR_SRC_ALPHA,  BlendFactor::ONE );
412   renderer.SetProperty( Renderer::Property::BLEND_FACTOR_DEST_ALPHA, BlendFactor::ONE );
413
414   // Each metaball has a different radius
415   mMetaballs[0].radius = mMetaballs[0].initRadius = 0.0145f;
416   mMetaballs[1].radius = mMetaballs[1].initRadius = 0.012f;
417   mMetaballs[2].radius = mMetaballs[2].initRadius = 0.0135f;
418   mMetaballs[3].radius = mMetaballs[3].initRadius = 0.0135f;
419
420   // Initialization of each of the metaballs
421   for( uint32_t i = 0 ; i < METABALL_NUMBER ; i++ )
422   {
423     mMetaballs[i].position = Vector2(0.0f, 0.0f);
424
425     mMetaballs[i].actor = Actor::New();
426     mMetaballs[i].actor.SetName( "Metaball" );
427     mMetaballs[i].actor.SetScale( 1.0f );
428     mMetaballs[i].actor.SetParentOrigin( ParentOrigin::CENTER );
429
430
431     mMetaballs[i].actor.AddRenderer( renderer );
432
433     mMetaballs[i].positionIndex = mMetaballs[i].actor.RegisterProperty( "uPositionMetaball", mMetaballs[i].position );
434     mMetaballs[i].positionVarIndex = mMetaballs[i].actor.RegisterProperty( "uPositionVar", Vector2(0.f,0.f) );
435     mMetaballs[i].gravityIndex = mMetaballs[i].actor.RegisterProperty( "uGravityVector", Vector2(0.f,0.f) );
436     mMetaballs[i].radiusIndex = mMetaballs[i].actor.RegisterProperty( "uRadius", mMetaballs[i].radius );
437     mMetaballs[i].radiusVarIndex = mMetaballs[i].actor.RegisterProperty( "uRadiusVar", 0.f );
438     mMetaballs[i].aspectIndex = mMetaballs[i].actor.RegisterProperty( "uAspect", aspect );
439   }
440
441   //Root creation
442   mMetaballRoot = Actor::New();
443   mMetaballRoot.SetParentOrigin( ParentOrigin::CENTER );
444   for( uint32_t i = 0 ; i < METABALL_NUMBER ; i++ )
445   {
446     mMetaballRoot.Add( mMetaballs[i].actor );
447   }
448 }
449
450 void MetaballRefracController::CreateMetaballImage()
451 {
452   // Create an FBO and a render task to create to render the metaballs with a fragment shader
453   Stage stage = Stage::GetCurrent();
454   mMetaballFBO = FrameBuffer::New( mScreenSize.x, mScreenSize.y, FrameBuffer::Attachment::NONE );
455   mMetaballFBOTexture = Texture::New( Dali::TextureType::TEXTURE_2D,
456                                       Pixel::RGB888,
457                                       mScreenSize.x, mScreenSize.y );
458   mMetaballFBO.AttachColorTexture( mMetaballFBOTexture );
459
460   stage.Add(mMetaballRoot);
461
462   //Creation of the render task used to render the metaballs
463   RenderTaskList taskList = Stage::GetCurrent().GetRenderTaskList();
464   RenderTask task = taskList.CreateTask();
465   task.SetRefreshRate( RenderTask::REFRESH_ALWAYS );
466   task.SetSourceActor( mMetaballRoot );
467   task.SetExclusive( true );
468   task.SetClearColor( Color::BLACK );
469   task.SetClearEnabled( true );
470   task.SetFrameBuffer( mMetaballFBO );
471 }
472
473 void MetaballRefracController::CreateComposition()
474 {
475   // Create Refraction shader and renderer
476   mShaderRefraction = Shader::New( METABALL_VERTEX_SHADER, REFRACTION_FRAG_SHADER );
477
478   // Create new texture set
479   mTextureSetRefraction = TextureSet::New();
480   mTextureSetRefraction.SetTexture( 0u, mBackgroundTexture  );
481   mTextureSetRefraction.SetTexture( 1u, mMetaballFBOTexture );
482
483   // Create normal shader
484   mShaderNormal = Shader::New( METABALL_VERTEX_SHADER, FRAG_SHADER );
485
486   // Create new texture set
487   mTextureSetNormal = TextureSet::New();
488   mTextureSetNormal.SetTexture( 0u, mBackgroundTexture );
489
490   // Create actor
491   mCompositionActor = Actor::New( );
492   mCompositionActor.SetParentOrigin(ParentOrigin::CENTER);
493   mCompositionActor.SetPosition(Vector3(0.0f, 0.0f, 0.0f));
494   mCompositionActor.SetSize(mScreenSize.x, mScreenSize.y);
495
496   // Create geometry
497   Geometry metaballGeometry = CreateGeometry( false );
498   mRendererRefraction = Renderer::New( metaballGeometry, mShaderNormal );
499   mRendererRefraction.SetTextures( mTextureSetNormal );
500   mCompositionActor.AddRenderer( mRendererRefraction );
501
502   Stage stage = Stage::GetCurrent();
503   stage.Add( mCompositionActor );
504 }
505
506 void MetaballRefracController::CreateAnimations()
507 {
508   uint32_t i = 0;
509   float key;
510
511   mPositionVarAnimation[1] = Animation::New( 2.f );
512   mPositionVarAnimation[1].SetLooping( false );
513   mPositionVarAnimation[1].Pause();
514   mPositionVarAnimation[1].FinishedSignal().Connect( this, &MetaballRefracController::LaunchGetBackToPositionAnimation );
515
516   KeyFrames keySinCosVariation = KeyFrames::New();
517   Vector2 sinCosVariation(0,0);
518   for( i = 0 ; i < 360; i++ )
519   {
520     sinCosVariation.x = 0.05f * ( -sinf(i * Math::PI_OVER_180) + cosf(i * Math::PI_OVER_180) );
521     sinCosVariation.y = 0.05f * ( sinf(i * Math::PI_OVER_180) - cosf(i * Math::PI_OVER_180) );
522     key = i/360.f;
523     keySinCosVariation.Add(key, sinCosVariation);
524   }
525
526   mPositionVarAnimation[2] = Animation::New(6.f);
527   mPositionVarAnimation[2].AnimateBetween(Property( mMetaballs[2].actor, mMetaballs[2].positionVarIndex ), keySinCosVariation);
528   mPositionVarAnimation[2].SetLooping( true );
529   mPositionVarAnimation[2].Pause();
530
531   KeyFrames keyCosSinVariation = KeyFrames::New();
532   Vector2 cosSinVariation(0,0);
533   for( i = 0 ; i < 360; i++ )
534   {
535     cosSinVariation.x = 0.05f * ( -sinf(i * Math::PI_OVER_180) - cosf(i * Math::PI_OVER_180) );
536     cosSinVariation.y = 0.05f * ( sinf(i * Math::PI_OVER_180) + cosf(i * Math::PI_OVER_180) );
537     key = i/360.f;
538     keyCosSinVariation.Add(key, cosSinVariation);
539   }
540
541   mPositionVarAnimation[3] = Animation::New(6.f);
542   mPositionVarAnimation[3].AnimateBetween(Property( mMetaballs[3].actor, mMetaballs[3].positionVarIndex ), keyCosSinVariation);
543   mPositionVarAnimation[3].SetLooping( true );
544   mPositionVarAnimation[3].Pause();
545
546   //Animations for gravity
547   for( i = 0 ; i < METABALL_NUMBER; i++ )
548   {
549     mGravityAnimation[i] = Animation::New( 25.f );
550     mGravityAnimation[i].AnimateBy( Property( mMetaballs[i].actor, mMetaballs[i].gravityIndex ), mGravity * 25.f * 3.f );
551     mGravityAnimation[i].SetLooping( false );
552     mGravityAnimation[i].Pause();
553   }
554
555   //Animation to decrease size of metaballs when there is no click
556   for( i = 0 ; i < METABALL_NUMBER; i++ )
557   {
558     mRadiusDecAnimation[i] = Animation::New( 25.f );
559     mRadiusDecAnimation[i].AnimateBy( Property( mMetaballs[i].actor, mMetaballs[i].radiusIndex ), -0.004f * 25.f * 3.f );
560     mRadiusDecAnimation[i].SetLooping( false );
561     mRadiusDecAnimation[i].Pause();
562   }
563
564   // Animation to grow the size of the metaballs the first second of the click
565   for( i = 0 ; i < METABALL_NUMBER; i++ )
566   {
567     mRadiusIncFastAnimation[i] = Animation::New( 0.3f );
568     mRadiusIncFastAnimation[i].AnimateBy( Property( mMetaballs[i].actor, mMetaballs[i].radiusIndex ), 0.06f );
569     mRadiusIncFastAnimation[i].SetLooping( false );
570     mRadiusIncFastAnimation[i].Pause();
571   }
572   mRadiusIncFastAnimation[0].FinishedSignal().Connect( this, &MetaballRefracController::LaunchRadiusIncSlowAnimations );
573
574   // Animation to grow the size of the metaballs afterwards
575   for( i = 0 ; i < METABALL_NUMBER; i++ )
576   {
577     mRadiusIncSlowAnimation[i] = Animation::New( 20.f );
578     mRadiusIncSlowAnimation[i].AnimateBy( Property( mMetaballs[i].actor, mMetaballs[i].radiusIndex ), 0.04f );
579     mRadiusIncSlowAnimation[i].SetLooping( false );
580     mRadiusIncSlowAnimation[i].Pause();
581   }
582
583   // Keyframes of a sin function
584   KeyFrames keySin = KeyFrames::New();
585   float val;
586   for( i = 0 ; i < 360; i++ )
587   {
588     val = 0.01f * sin(i * Math::PI/180.f);
589     key = i/360.f;
590     keySin.Add(key, val);
591   }
592
593   //Animation to change the size of the metaball
594   mRadiusVarAnimation[2] = Animation::New( 8.f );
595   mRadiusVarAnimation[2].AnimateBetween( Property( mMetaballs[2].actor, mMetaballs[2].radiusVarIndex ), keySin );
596   mRadiusVarAnimation[2].SetLooping( true );
597
598   // Keyframes of a cos function
599   KeyFrames keyCos = KeyFrames::New();
600   for( i = 0 ; i < 360; i++ )
601   {
602     val = 0.01f * cos(i * Math::PI/180.f);
603     key = i/360.f;
604     keyCos.Add(key, val);
605   }
606
607   //Animation to change the size of the metaball
608   mRadiusVarAnimation[3] = Animation::New( 8.f );
609   mRadiusVarAnimation[3].AnimateBetween( Property( mMetaballs[3].actor, mMetaballs[3].radiusVarIndex ), keyCos );
610   mRadiusVarAnimation[3].SetLooping( true );
611 }
612
613 void MetaballRefracController::LaunchGetBackToPositionAnimation( Animation& source )
614 {
615   mMetaballPosVariationTo = Vector2(0,0);
616
617   mPositionVarAnimation[1] = Animation::New( 1.f );
618   mPositionVarAnimation[1].SetLooping( false );
619   mPositionVarAnimation[1].AnimateTo(Property( mMetaballs[1].actor, mMetaballs[1].positionVarIndex ), Vector2(0,0) );
620   mPositionVarAnimation[1].Play();
621 }
622
623 void MetaballRefracController::LaunchRadiusIncSlowAnimations( Animation& source )
624 {
625   for( uint32_t i = 0 ; i < METABALL_NUMBER; i++ )
626   {
627     mRadiusIncSlowAnimation[i].Play();
628   }
629   mPositionVarAnimation[2].Play();
630   mPositionVarAnimation[3].Play();
631 }
632
633 void MetaballRefracController::StopClickAnimations()
634 {
635   for( uint32_t i = 0 ; i < METABALL_NUMBER; i++ )
636   {
637     mRadiusIncSlowAnimation[i].Stop();
638     mRadiusIncFastAnimation[i].Stop();
639   }
640   mPositionVarAnimation[1].Stop();
641   mPositionVarAnimation[2].Stop();
642   mPositionVarAnimation[3].Stop();
643 }
644
645 void MetaballRefracController::StopAfterClickAnimations()
646 {
647   for( uint32_t i = 0 ; i < METABALL_NUMBER; i++ )
648   {
649     mGravityAnimation[i].Stop();
650     mRadiusDecAnimation[i].Stop();
651
652     mMetaballs[i].radius = mMetaballs[i].initRadius;
653
654     mMetaballs[i].actor.SetProperty( mMetaballs[i].gravityIndex, Vector2(0,0) );
655     mMetaballs[i].actor.SetProperty( mMetaballs[i].radiusIndex, mMetaballs[i].radius );
656     mMetaballs[i].actor.SetProperty( mMetaballs[i].radiusVarIndex, 0.f );
657   }
658   mRadiusVarAnimation[2].Stop();
659   mRadiusVarAnimation[3].Stop();
660 }
661
662 void MetaballRefracController::ResetMetaballsState()
663 {
664   mRendererRefraction.SetTextures( mTextureSetNormal );
665   mRendererRefraction.SetShader( mShaderNormal );
666
667   for( uint32_t i = 0 ; i < METABALL_NUMBER; i++ )
668   {
669     mMetaballs[i].radius = mMetaballs[i].initRadius;
670   }
671
672   mMetaballPosVariationTo = Vector2(0,0);
673   mMetaballPosVariationFrom = Vector2(0,0);
674   mMetaballPosVariation = Vector2(0,0);
675   mGravityVar = Vector2(0,0);
676 }
677
678 void MetaballRefracController::SetPositionToMetaballs( const Vector2& metaballCenter )
679 {
680   //We set the position for the metaballs based on click position
681   for( uint32_t i = 0 ; i < METABALL_NUMBER; i++ )
682   {
683     mMetaballs[i].position = metaballCenter;
684     mMetaballs[i].actor.SetProperty( mMetaballs[i].positionIndex, mMetaballs[i].position );
685   }
686 }
687
688 bool MetaballRefracController::OnTouch( Actor actor, const TouchData& touch )
689 {
690   const float aspect = mScreenSize.y / mScreenSize.x;
691   switch( touch.GetState( 0 ) )
692   {
693     case PointState::DOWN:
694     {
695       StopAfterClickAnimations();
696       for( uint32_t i = 0 ; i < METABALL_NUMBER; i++ )
697       {
698         mRadiusIncFastAnimation[i].Play();
699       }
700       mRadiusVarAnimation[2].Play();
701       mRadiusVarAnimation[3].Play();
702
703       //We draw with the refraction-composition shader
704       mRendererRefraction.SetTextures( mTextureSetRefraction );
705       mRendererRefraction.SetShader( mShaderRefraction );
706       mCurrentTouchPosition = touch.GetScreenPosition( 0 );
707
708       //we use the click position for the metaballs
709       Vector2 metaballCenter = Vector2( (mCurrentTouchPosition.x / mScreenSize.x) - 0.5f,
710                                         (aspect * (mScreenSize.y - mCurrentTouchPosition.y) / mScreenSize.y) - 0.5f ) * 2.0f;
711       SetPositionToMetaballs(metaballCenter);
712       break;
713     }
714     case PointState::MOTION:
715     {
716       Vector2 screen = touch.GetScreenPosition( 0 );
717       Vector2 displacement = screen - mCurrentTouchPosition;
718       mCurrentTouchPosition = screen;
719
720       mMetaballPosVariationTo.x += ( displacement.x / mScreenSize.x ) * 2.2f;
721       mMetaballPosVariationTo.y += (-displacement.y / mScreenSize.y ) * 2.2f;
722
723       if (mPositionVarAnimation[1])
724       {
725         mPositionVarAnimation[1].FinishedSignal().Disconnect( this, &MetaballRefracController::LaunchGetBackToPositionAnimation );
726         mPositionVarAnimation[1].Stop();
727       }
728       mPositionVarAnimation[1] = Animation::New( 1.f );
729       mPositionVarAnimation[1].SetLooping( false );
730       mPositionVarAnimation[1].AnimateTo(Property( mMetaballs[1].actor, mMetaballs[1].positionVarIndex ), mMetaballPosVariationTo );
731       mPositionVarAnimation[1].FinishedSignal().Connect( this, &MetaballRefracController::LaunchGetBackToPositionAnimation );
732       mPositionVarAnimation[1].Play();
733
734       //we use the click position for the metaballs
735       Vector2 metaballCenter = Vector2( (screen.x / mScreenSize.x) - 0.5f,
736                                         (aspect * (mScreenSize.y - screen.y) / mScreenSize.y) - 0.5f) * 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.state == 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 }