Resurrected Metaball effects 43/193943/3
authorKimmo Hoikka <kimmo.hoikka@samsung.com>
Tue, 27 Nov 2018 18:18:21 +0000 (18:18 +0000)
committerKimmo Hoikka <kimmo.hoikka@samsung.com>
Thu, 29 Nov 2018 13:51:24 +0000 (13:51 +0000)
Fixed to use the new Render APIs, removed unused normals from Refraction example

Change-Id: I3bd680410c64a2d3e5ab5ca6d5d670653eb1036d

15 files changed:
demo/dali-demo.cpp
examples/image-view-url/image-view-url-example.cpp
examples/metaball-explosion/metaball-explosion-example.cpp [new file with mode: 0644]
examples/metaball-refrac/metaball-refrac-example.cpp [new file with mode: 0644]
resources/po/as.po
resources/po/de.po
resources/po/en_GB.po
resources/po/en_US.po
resources/po/es.po
resources/po/fi.po
resources/po/ko.po
resources/po/ml.po
resources/po/ur.po
resources/po/zn_CH.po
shared/dali-demo-strings.h

index 379758f..70da658 100644 (file)
@@ -44,6 +44,8 @@ int DALI_EXPORT_API main(int argc, char **argv)
   demo.AddExample(Example("fpp-game.example", DALI_DEMO_STR_TITLE_FPP_GAME));
   demo.AddExample(Example("item-view.example", DALI_DEMO_STR_TITLE_ITEM_VIEW));
   demo.AddExample(Example("mesh-visual.example", DALI_DEMO_STR_TITLE_MESH_VISUAL));
+  demo.AddExample(Example("metaball-explosion.example", DALI_DEMO_STR_TITLE_METABALL_EXPLOSION));
+  demo.AddExample(Example("metaball-refrac.example", DALI_DEMO_STR_TITLE_METABALL_REFRAC));
   demo.AddExample(Example("motion-blur.example", DALI_DEMO_STR_TITLE_MOTION_BLUR));
   demo.AddExample(Example("refraction-effect.example", DALI_DEMO_STR_TITLE_REFRACTION));
   demo.AddExample(Example("renderer-stencil.example", DALI_DEMO_STR_TITLE_RENDERER_STENCIL));
index 59ebda9..624709e 100644 (file)
@@ -139,7 +139,7 @@ private:
                                     Pixel::RGB888,
                                     unsigned(TARGET_SIZE.width),
                                     unsigned(TARGET_SIZE.height));
-      auto framebuffer = FrameBuffer::New(TARGET_SIZE.width, TARGET_SIZE.height, Pixel::RGB888);
+      auto framebuffer = FrameBuffer::New(TARGET_SIZE.width, TARGET_SIZE.height, FrameBuffer::Attachment::NONE );
       framebuffer.AttachColorTexture(mOutputTexture);
 
       renderTask.SetFrameBuffer(framebuffer);
diff --git a/examples/metaball-explosion/metaball-explosion-example.cpp b/examples/metaball-explosion/metaball-explosion-example.cpp
new file mode 100644 (file)
index 0000000..a7fdd82
--- /dev/null
@@ -0,0 +1,697 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <cstdio>
+#include <string>
+#include <cstdint> // uint32_t, uint16_t etc
+
+#include <dali/public-api/rendering/renderer.h>
+#include <dali/public-api/rendering/texture.h>
+#include <dali/public-api/rendering/texture-set.h>
+#include <dali/public-api/rendering/frame-buffer.h>
+#include <dali/public-api/math/random.h>
+
+// INTERNAL INCLUDES
+#include "shared/utility.h" // DemoHelper::LoadTexture
+
+using namespace Dali;
+
+namespace // unnamed namespace for constants
+{
+// background image
+const char * const BACKGROUND_IMAGE( DEMO_IMAGE_DIR "background-2.jpg" );
+
+// number of metaballs
+constexpr uint32_t METABALL_NUMBER = 6;
+
+/**
+ * Vertex shader code for metaball
+ */
+const char* const METABALL_VERTEX_SHADER = DALI_COMPOSE_SHADER (
+    attribute mediump vec2    aPosition;\n
+    attribute mediump vec2    aTexture;\n
+    uniform   mediump mat4    uMvpMatrix;\n
+    uniform   mediump vec3    uSize;\n
+    uniform   lowp    vec4    uColor;\n
+    varying   mediump vec2    vTexCoord;\n
+
+    void main()\n
+    {\n
+      vTexCoord = aTexture;\n
+      mediump vec4 vertexPosition = vec4(aPosition.x, aPosition.y, 0.0, 1.0);\n
+      gl_Position = uMvpMatrix * vertexPosition;\n
+    }\n
+);
+
+/**
+ * Fragment shader code for metaball
+ */
+const char* const METABALL_FRAG_SHADER = DALI_COMPOSE_SHADER (
+  precision mediump float;\n
+  varying vec2 vTexCoord;\n
+  uniform vec2 uPositionMetaball;\n
+  uniform vec2 uPositionVar;\n
+  uniform vec2 uGravityVector;\n
+  uniform float uRadius;\n
+  uniform float uRadiusVar;\n
+  void main()\n
+  {\n
+    vec2 adjustedCoords = vTexCoord * 2.0 - 1.0;\n
+    vec2 finalMetaballPosition = uPositionMetaball + uGravityVector + uPositionVar;\n
+    \n
+    float finalRadius = uRadius + uRadiusVar;\n
+    vec2 distanceVec = adjustedCoords - finalMetaballPosition;\n
+    float result = dot(distanceVec, distanceVec);\n
+    float color = inversesqrt(result) * finalRadius;\n
+    \n
+    gl_FragColor = vec4(color,color,color,1.0);\n
+  }\n
+);
+
+/**
+ * Fragment shader code for metaball and background composition with refraction effect
+ */
+const char* const REFRACTION_FRAG_SHADER = DALI_COMPOSE_SHADER (
+  precision highp float;\n
+  varying vec2 vTexCoord;\n
+  uniform sampler2D sTexture;\n
+  uniform sampler2D sEffect;\n
+  uniform vec2 uPositionMetaball;\n
+  void main()\n
+  {\n
+    vec2 zoomCoords;\n
+    vec3 normal = vec3(0.0,0.0,1.0);\n
+    vec2 fakePos = vec2(0.0,0.0);\n
+    vec3 color = vec3(1.0, 1.0, 1.0);
+    float ambient = 0.2;
+    \n
+    vec4 metaColor = texture2D(sEffect, vTexCoord);\n
+    \n
+    vec2 adjustedCoords = vTexCoord.xy * vec2(2.0) - vec2(1.0);\n
+    fakePos = adjustedCoords.xy - vec2(uPositionMetaball.x, -uPositionMetaball.y);
+    float len = length(fakePos) + 0.01;\n
+    vec3 colorPos = vec3(0,0,1);
+    \n
+    if (metaColor.r > 0.85)\n
+    {\n
+      zoomCoords = ((vTexCoord - 0.5) * 0.9);\n
+      zoomCoords = zoomCoords + 0.5;\n
+      \n
+      float interpNormal = mix(0.7, 1.0, (metaColor.r - 0.85) * 4.);\n
+      normal.xyz = vec3(fakePos.x * (1.0 - interpNormal) / len, fakePos.y * (1.0 - interpNormal) / len, interpNormal);\n
+      normal.xyz = normalize(normal.xyz);\n
+      color = vec3(0.65, 1.0, 0);\n
+      colorPos = vec3(fakePos.x,fakePos.y,0);
+    }\n
+    else if (metaColor.r > 0.75)\n
+    {\n
+      float interpolation = mix(0.9, 1.15, (0.85 - metaColor.r) * 10.0);\n
+      zoomCoords = ((vTexCoord - 0.5) * interpolation);\n
+      zoomCoords = zoomCoords + 0.5;\n
+      \n
+      float interpNormal = mix(0.7, 0.0, (0.85 - metaColor.r) * 10.0);\n
+      normal.xyz = vec3(fakePos.x * (1.0 - interpNormal) / len, fakePos.y * (1.0 - interpNormal) / len, interpNormal);\n
+      normal.xyz = normalize(normal.xyz);\n
+      color = vec3(0.65, 1.0, 0);\n
+      colorPos = vec3(fakePos.x,fakePos.y,0);
+    }\n
+    else\n
+    {\n
+      zoomCoords = vTexCoord;\n
+      normal = vec3(0,0,0);\n
+      ambient = 0.5;\n
+    }\n
+    \n
+    vec3 lightPosition = vec3(-750.0,-1000.0,2000.0);\n
+    vec3 vertex = vec3(adjustedCoords.x,adjustedCoords.y,0.0);\n
+    \n
+    vec3 vecToLight = normalize( lightPosition - vertex );\n
+    \n
+    float lightDiffuse = dot( vecToLight, normal );\n
+    lightDiffuse = max(0.0,lightDiffuse);\n
+    lightDiffuse = lightDiffuse * 0.5 + 0.5;
+    \n
+    vec3 vertexToEye = vec3(0,0,1) - vertex;\n
+    vertexToEye = normalize(vertexToEye);
+    vec3 lightReflect = normalize(reflect(-vecToLight, normal));\n
+    float specularFactor = max(0.0,dot(vertexToEye, lightReflect));\n
+    specularFactor = pow(specularFactor, 32.0) * 0.7;
+    \n
+    vec4 texColor = texture2D(sTexture, zoomCoords);\n
+    gl_FragColor.rgb = texColor.rgb * ambient + color.rgb * texColor.rgb * lightDiffuse + vec3(specularFactor);\n
+    gl_FragColor.a = 1.0;
+  }\n
+ );
+
+/**
+ * Metadata for each ball
+ */
+struct MetaballInfo
+{
+  Actor         actor;
+  Vector2       position;
+  float         radius;
+  float         initRadius;
+
+  //new shader stuff
+  Property::Index positionIndex;
+  Property::Index positionVarIndex;
+};
+
+} // unnamed namespace
+
+/**
+ * Demo using Metaballs
+ *
+ * When the metaball is clicked it explodes to smaller balls
+ */
+class MetaballExplosionController : public ConnectionTracker
+{
+public:
+
+  /**
+   * Constructor
+   * @param application
+   */
+  MetaballExplosionController( Application& application );
+
+  /**
+   * Destructor
+   */
+  virtual ~MetaballExplosionController();
+
+  /**
+   * Creates the metaballs and initializes the scene
+   */
+  void Create( Application& app );
+
+  /**
+   * Touch event handler to center metaballs at touch position
+   * and start explosion animation on release
+   */
+  bool OnTouch( Actor actor, const TouchData& touch );
+
+  /**
+   * Key event handler to quit application on escape or back key
+   */
+  void OnKeyEvent(const KeyEvent& event);
+
+private: // Data
+
+  Application&      mApplication;
+  Vector2           mScreenSize;
+
+  Texture           mBackgroundTexture;
+  FrameBuffer       mMetaballFBO;
+  Texture           mMetaballFBOTexture;
+
+  Actor             mMetaballRoot;
+  MetaballInfo      mMetaballs[METABALL_NUMBER];
+
+  Property::Index   mPositionIndex;
+  Actor             mCompositionActor;
+
+  //Motion
+  Vector2           mCurrentTouchPosition;
+  Vector2           mMetaballPosVariation;
+  Vector2           mMetaballPosVariationFrom;
+  Vector2           mMetaballPosVariationTo;
+  Vector2           mMetaballCenter;
+
+  //Animations
+  Animation         mPositionVarAnimation[METABALL_NUMBER];
+
+  uint32_t          mDispersion;
+  Animation         mDispersionAnimation[METABALL_NUMBER];
+
+  Timer             mTimerDispersion;
+
+  float             mTimeMultiplier;
+
+  // Private helper functions
+
+  /**
+   * Create a mesh data with the geometry for the metaball rendering
+   * @param aspectMappedTexture whether texture coords should be mapped based on aspect ratio
+   */
+  Geometry CreateGeometry( bool aspectMappedTexture = true );
+
+  /**
+   * Create a actors and renderers for the metaballs
+   */
+  void CreateMetaballActors();
+
+  /**
+   * Create the render task and FBO to render the metaballs into a texture
+   */
+  void CreateMetaballImage();
+
+  /**
+   * Create the the final composition
+   */
+  void CreateComposition();
+
+  /**
+   * Function to create animations for the small variations of position inside the metaball
+   */
+  void CreateAnimations();
+
+  /**
+   * Function to reset metaball state
+   */
+  void ResetMetaballs( bool resetAnims );
+
+  /**
+   * Function to create disperse each of the ball that compose the metaball when exploding
+   */
+  void DisperseBallAnimation( uint32_t ball );
+
+  /**
+   * Function to make metaballs come back to reset position
+   */
+  void LaunchResetMetaballPosition( Animation& source );
+
+  /**
+   * Function to set things at the end of the animation
+   */
+  void EndDisperseAnimation( Animation& source );
+
+  /**
+   * Function to init dispersion of the metaballs one by one using a timer
+   * (so not all the balls begin moving at the same time)
+   */
+  bool OnTimerDispersionTick();
+
+  /**
+   * Function to set the actual position of the metaballs when the user clicks the screen
+   */
+  void SetPositionToMetaballs( const Vector2& metaballCenter );
+};
+
+/**
+ * Implementation
+ */
+
+MetaballExplosionController::MetaballExplosionController( Application& application )
+: mApplication( application ),
+  mScreenSize(),
+  mBackgroundTexture(),
+  mMetaballFBO(),
+  mMetaballFBOTexture(),
+  mMetaballRoot(),
+  mMetaballs(),
+  mPositionIndex(),
+  mCompositionActor(),
+  mCurrentTouchPosition(),
+  mMetaballPosVariation(),
+  mMetaballPosVariationFrom(),
+  mMetaballPosVariationTo(),
+  mMetaballCenter(),
+  mPositionVarAnimation(),
+  mDispersion( 0 ),
+  mDispersionAnimation(),
+  mTimerDispersion(),
+  mTimeMultiplier( 1.0f )
+{
+  // Connect to the Application's Init signal
+  mApplication.InitSignal().Connect( this, &MetaballExplosionController::Create );
+}
+
+MetaballExplosionController::~MetaballExplosionController()
+{
+  // Nothing to do here;
+}
+
+void MetaballExplosionController::Create( Application& app )
+{
+  Stage stage = Stage::GetCurrent();
+
+  stage.KeyEventSignal().Connect( this, &MetaballExplosionController::OnKeyEvent );
+
+  mScreenSize = stage.GetSize();
+
+  mTimeMultiplier = 1.0f;
+
+  stage.SetBackgroundColor(Color::BLACK);
+
+  // Load background texture
+  mBackgroundTexture = DemoHelper::LoadTexture( BACKGROUND_IMAGE );
+
+  srand( static_cast<uint32_t>( time(0) ) );
+
+  //Create internal data
+  CreateMetaballActors();
+  CreateMetaballImage();
+  CreateComposition();
+
+  CreateAnimations();
+
+  mDispersion = 0;
+  mTimerDispersion = Timer::New( 150 );
+  mTimerDispersion.TickSignal().Connect( this, &MetaballExplosionController::OnTimerDispersionTick );
+
+  // Connect the callback to the touch signal on the mesh actor
+  stage.GetRootLayer().TouchSignal().Connect( this, &MetaballExplosionController::OnTouch );
+}
+
+Geometry MetaballExplosionController::CreateGeometry( bool aspectMappedTexture )
+{
+  const float aspect = mScreenSize.y / mScreenSize.x;
+
+  // Create vertices and specify their color
+  const float xsize = mScreenSize.x * 0.5;
+
+  // Create the meshdata for the metaballs
+  struct VertexPosition { Vector2 position; };
+  struct VertexTexture { Vector2 texture; };
+
+  VertexPosition vertices[] =
+  {
+    { Vector2( -xsize, -xsize * aspect ) },
+    { Vector2(  xsize, -xsize * aspect ) },
+    { Vector2( -xsize,  xsize * aspect ) },
+    { Vector2(  xsize,  xsize * aspect ) }
+  };
+
+  const float textureAspect = (aspectMappedTexture) ? aspect : 1.0f;
+  VertexTexture textures[] =
+  {
+    { Vector2( 0.0f, 0.0f ) },
+    { Vector2( 1.0f, 0.0f ) },
+    { Vector2( 0.0f, 1.0f * textureAspect ) },
+    { Vector2( 1.0f, 1.0f * textureAspect ) }
+  };
+
+  uint32_t numberOfVertices = sizeof(vertices)/sizeof(VertexPosition);
+
+  // Vertices
+  Property::Map positionVertexFormat;
+  positionVertexFormat["aPosition"] = Property::VECTOR2;
+  PropertyBuffer positionVertices = PropertyBuffer::New( positionVertexFormat );
+  positionVertices.SetData( vertices, numberOfVertices );
+
+  // Textures
+  Property::Map textureVertexFormat;
+  textureVertexFormat["aTexture"] = Property::VECTOR2;
+  PropertyBuffer textureVertices = PropertyBuffer::New( textureVertexFormat );
+  textureVertices.SetData( textures, numberOfVertices );
+
+  // Indices
+  const uint16_t indices[] = { 0, 3, 1, 0, 2, 3 };
+
+  // Create the geometry object
+  Geometry texturedQuadGeometry = Geometry::New();
+  texturedQuadGeometry.AddVertexBuffer( positionVertices );
+  texturedQuadGeometry.AddVertexBuffer( textureVertices );
+
+  texturedQuadGeometry.SetIndexBuffer ( &indices[0], sizeof( indices )/ sizeof( indices[0] ) );
+
+  return texturedQuadGeometry;
+}
+
+void MetaballExplosionController::CreateMetaballActors()
+{
+  // Create the shader for the metaballs, tell DALi that shader modifies geometry so we dont need to set a meaningless size
+  Shader shader = Shader::New( METABALL_VERTEX_SHADER, METABALL_FRAG_SHADER, Shader::Hint::MODIFIES_GEOMETRY );
+
+  Geometry metaballGeom = CreateGeometry();
+  // Reuse same renderer for each actor
+  Renderer renderer = Renderer::New( metaballGeom, shader );
+  renderer.SetProperty( Renderer::Property::BLEND_MODE, BlendMode::ON );
+  renderer.SetProperty( Renderer::Property::BLEND_FACTOR_SRC_RGB,    BlendFactor::ONE );
+  renderer.SetProperty( Renderer::Property::BLEND_FACTOR_DEST_RGB,   BlendFactor::ONE );
+  renderer.SetProperty( Renderer::Property::BLEND_FACTOR_SRC_ALPHA,  BlendFactor::ONE );
+  renderer.SetProperty( Renderer::Property::BLEND_FACTOR_DEST_ALPHA, BlendFactor::ONE  );
+
+  //Initialization of each of the metaballs
+  for( uint32_t i = 0; i < METABALL_NUMBER; i++ )
+  {
+    mMetaballs[i].position = Vector2(0.0f, 0.0f);
+    mMetaballs[i].radius = mMetaballs[i].initRadius = Random::Range(0.05f,0.07f);
+
+    mMetaballs[i].actor = Actor::New( );
+    mMetaballs[i].actor.SetName( "Metaball" );
+    mMetaballs[i].actor.SetScale( 1.0f );
+    mMetaballs[i].actor.SetParentOrigin( ParentOrigin::CENTER );
+    mMetaballs[i].actor.AddRenderer( renderer );
+
+    mMetaballs[i].positionIndex = mMetaballs[i].actor.RegisterProperty( "uPositionMetaball", mMetaballs[i].position );
+
+    mMetaballs[i].positionVarIndex = mMetaballs[i].actor.RegisterProperty( "uPositionVar", Vector2(0.f,0.f) );
+
+    mMetaballs[i].actor.RegisterProperty( "uGravityVector", Vector2(Random::Range(-0.2,0.2),Random::Range(-0.2,0.2)) );
+    mMetaballs[i].actor.RegisterProperty( "uRadius", mMetaballs[i].radius );
+    mMetaballs[i].actor.RegisterProperty( "uRadiusVar", 0.f );
+  }
+
+  // Root creation
+  mMetaballRoot = Actor::New();
+  mMetaballRoot.SetParentOrigin( ParentOrigin::CENTER );
+  for( uint32_t i = 0; i < METABALL_NUMBER; i++ )
+  {
+    mMetaballRoot.Add( mMetaballs[i].actor );
+  }
+
+}
+
+void MetaballExplosionController::CreateMetaballImage()
+{
+  // Create an FBO and a render task to create to render the metaballs with a fragment shader
+  Stage stage = Stage::GetCurrent();
+
+  mMetaballFBO = FrameBuffer::New( mScreenSize.x, mScreenSize.y, FrameBuffer::Attachment::NONE );
+  mMetaballFBOTexture = Texture::New( Dali::TextureType::TEXTURE_2D,
+                                      Pixel::RGB888,
+                                      mScreenSize.x, mScreenSize.y );
+  mMetaballFBO.AttachColorTexture( mMetaballFBOTexture );
+
+  stage.Add(mMetaballRoot);
+
+  // Create the render task used to render the metaballs
+  RenderTaskList taskList = Stage::GetCurrent().GetRenderTaskList();
+  RenderTask task = taskList.CreateTask();
+  task.SetRefreshRate( RenderTask::REFRESH_ALWAYS );
+  task.SetSourceActor( mMetaballRoot );
+  task.SetExclusive( true );
+  task.SetClearColor( Color::BLACK );
+  task.SetClearEnabled( true );
+  task.SetFrameBuffer( mMetaballFBO );
+}
+
+void MetaballExplosionController::CreateComposition()
+{
+  //Create new shader
+  Shader shader = Shader::New( METABALL_VERTEX_SHADER, REFRACTION_FRAG_SHADER );
+
+  // Create new texture set
+  auto textureSet = TextureSet::New();
+  textureSet.SetTexture( 0u, mBackgroundTexture  );
+  textureSet.SetTexture( 1u, mMetaballFBOTexture );
+
+  // Create geometry
+  Geometry metaballGeom = CreateGeometry( false );
+
+  Renderer mRenderer = Renderer::New( metaballGeom, shader );
+  mRenderer.SetTextures( textureSet );
+
+  // Create actor
+  mCompositionActor = Actor::New( );
+  mCompositionActor.SetParentOrigin(ParentOrigin::CENTER);
+  mCompositionActor.SetPosition(Vector3(0.0f, 0.0f, 0.0f));
+  mCompositionActor.SetSize(mScreenSize.x, mScreenSize.y);
+  mCompositionActor.AddRenderer( mRenderer );
+
+  Vector2 metaballCenter(0.0,0);
+  metaballCenter.x = metaballCenter.x * 0.5;
+  metaballCenter.y = metaballCenter.y * 0.5;
+  mPositionIndex = mCompositionActor.RegisterProperty( "uPositionMetaball", metaballCenter );
+
+  SetPositionToMetaballs( metaballCenter );
+
+  mCompositionActor.SetSize(mScreenSize.x, mScreenSize.y);
+
+  Stage stage = Stage::GetCurrent();
+  stage.Add( mCompositionActor );
+}
+
+void MetaballExplosionController::CreateAnimations()
+{
+  Vector2 direction;
+
+  for( uint32_t i = 0; i < METABALL_NUMBER; i++ )
+  {
+    KeyFrames keySinCosVariation = KeyFrames::New();
+    Vector2 sinCosVariation( 0,0 );
+
+    direction.x = Random::Range( -100.f,100.f );
+    direction.y = Random::Range( -100.f,100.f );
+
+    direction.Normalize();
+    direction *= 0.1f;
+
+    for( uint32_t j = 0; j < 360; j++ )
+    {
+      sinCosVariation.x = sinf( j * Math::PI/180.f ) * direction.x;
+      sinCosVariation.y = cosf( j * Math::PI/180.f ) * direction.y;
+      float key = j/360.f;
+      keySinCosVariation.Add( key, sinCosVariation );
+    }
+
+    mPositionVarAnimation[i] = Animation::New( 3.f );
+    mPositionVarAnimation[i].AnimateBetween( Property( mMetaballs[i].actor, mMetaballs[i].positionVarIndex ), keySinCosVariation );
+    mPositionVarAnimation[i].SetLooping( true );
+    mPositionVarAnimation[i].Play();
+  }
+}
+
+void MetaballExplosionController::ResetMetaballs( bool resetAnims )
+{
+  for( uint32_t i = 0; i < METABALL_NUMBER; i++ )
+  {
+    if( mDispersionAnimation[i] )
+    {
+      mDispersionAnimation[i].Clear();
+    }
+
+    mMetaballs[i].position = Vector2( 0.0f, 0.0f );
+    mMetaballs[i].actor.SetProperty( mMetaballs[i].positionIndex, mMetaballs[i].position );
+  }
+  mTimerDispersion.Stop();
+  mDispersion = 0;
+
+  mCompositionActor.SetProperty( mPositionIndex, Vector2(0,0) );
+}
+
+void MetaballExplosionController::DisperseBallAnimation( uint32_t ball )
+{
+  Vector2 position;
+  position.x = Random::Range(-1.5f,1.5f);
+  position.y = Random::Range(-1.5f,1.5f);
+
+  mDispersionAnimation[ball] = Animation::New(2.0f * mTimeMultiplier);
+  mDispersionAnimation[ball].AnimateTo( Property(mMetaballs[ball].actor, mMetaballs[ball].positionIndex), position);
+  mDispersionAnimation[ball].Play();
+
+  if( ball == METABALL_NUMBER - 1 )
+  {
+    mDispersionAnimation[ball].FinishedSignal().Connect( this, &MetaballExplosionController::LaunchResetMetaballPosition );
+  }
+}
+
+void MetaballExplosionController::LaunchResetMetaballPosition( Animation& source )
+{
+  for( uint32_t i = 0; i < METABALL_NUMBER; i++ )
+  {
+    mDispersionAnimation[i] = Animation::New( 1.5f + i * 0.25f * mTimeMultiplier );
+    mDispersionAnimation[i].AnimateTo(Property( mMetaballs[i].actor, mMetaballs[i].positionIndex), Vector2(0,0) );
+    mDispersionAnimation[i].Play();
+
+    if( i == METABALL_NUMBER - 1 )
+    {
+      mDispersionAnimation[i].FinishedSignal().Connect( this, &MetaballExplosionController::EndDisperseAnimation );
+    }
+  }
+}
+
+void MetaballExplosionController::EndDisperseAnimation( Animation& source )
+{
+  mCompositionActor.SetProperty( mPositionIndex, Vector2(0,0) );
+}
+
+bool MetaballExplosionController::OnTimerDispersionTick()
+{
+  if( mDispersion < METABALL_NUMBER )
+  {
+    DisperseBallAnimation( mDispersion );
+    mDispersion++;
+  }
+  return true;
+}
+
+void MetaballExplosionController::SetPositionToMetaballs( const Vector2& metaballCenter )
+{
+  //We set the position for the metaballs based on click position
+  for( uint32_t i = 0; i < METABALL_NUMBER; i++ )
+  {
+    mMetaballs[i].position = metaballCenter;
+    mMetaballs[i].actor.SetProperty( mMetaballs[i].positionIndex, mMetaballs[i].position );
+  }
+
+  mCompositionActor.SetProperty( mPositionIndex, metaballCenter );
+}
+
+bool MetaballExplosionController::OnTouch( Actor actor, const TouchData& touch )
+{
+  float aspectR = mScreenSize.y / mScreenSize.x;
+
+  switch( touch.GetState( 0 ) )
+  {
+    case PointState::DOWN:
+    {
+      ResetMetaballs(true);
+
+      const Vector2 screen = touch.GetScreenPosition( 0 );
+      Vector2 metaballCenter = Vector2( (screen.x / mScreenSize.x) - 0.5f, (aspectR * (mScreenSize.y - screen.y) / mScreenSize.y) - 0.5f ) * 2.0f;
+      SetPositionToMetaballs(metaballCenter);
+
+      break;
+    }
+    case PointState::MOTION:
+    {
+      const Vector2 screen = touch.GetScreenPosition( 0 );
+      Vector2 metaballCenter = Vector2( (screen.x / mScreenSize.x) - 0.5f, (aspectR * (mScreenSize.y - screen.y) / mScreenSize.y) - 0.5f ) * 2.0f;
+      SetPositionToMetaballs(metaballCenter);
+      break;
+    }
+    case PointState::UP:
+    case PointState::LEAVE:
+    case PointState::INTERRUPTED:
+    {
+      mTimerDispersion.Start();
+      break;
+    }
+    default:
+      break;
+    }
+  return true;
+}
+
+void MetaballExplosionController::OnKeyEvent(const KeyEvent& event)
+{
+  if(event.state == KeyEvent::Down)
+  {
+    if( IsKey( event, Dali::DALI_KEY_ESCAPE) || IsKey( event, Dali::DALI_KEY_BACK) )
+    {
+      mApplication.Quit();
+    }
+  }
+}
+
+/**
+ * Main entry point
+ */
+int32_t DALI_EXPORT_API main( int argc, char **argv )
+{
+  Application application = Application::New( &argc, &argv );
+
+  MetaballExplosionController test( application );
+
+  application.MainLoop();
+
+  return 0;
+}
diff --git a/examples/metaball-refrac/metaball-refrac-example.cpp b/examples/metaball-refrac/metaball-refrac-example.cpp
new file mode 100644 (file)
index 0000000..8d1def8
--- /dev/null
@@ -0,0 +1,787 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <cstdio>
+#include <string>
+#include <cstdint> // uint32_t, uint16_t etc
+
+#include <dali/public-api/rendering/renderer.h>
+#include <dali/public-api/rendering/texture.h>
+#include <dali/public-api/rendering/texture-set.h>
+#include <dali/public-api/rendering/frame-buffer.h>
+
+// INTERNAL INCLUDES
+#include "shared/utility.h" // DemoHelper::LoadTexture
+
+using namespace Dali;
+
+namespace // unnamed namespace for constants
+{
+const char * const BACKGROUND_IMAGE( DEMO_IMAGE_DIR "background-2.jpg" );
+const float GRAVITY_X(0);
+const float GRAVITY_Y(-0.09);
+
+// number of metaballs
+constexpr uint32_t METABALL_NUMBER = 6;
+
+/**
+ * Vertex shader for metaballs
+ */
+const char* const METABALL_VERTEX_SHADER = DALI_COMPOSE_SHADER (
+    attribute mediump vec2    aPosition;\n
+    attribute mediump vec2    aTexture;\n
+    uniform   mediump mat4    uMvpMatrix;\n
+    uniform   mediump vec3    uSize;\n
+    uniform   lowp    vec4    uColor;\n
+    varying   mediump vec2    vTexCoord;\n
+
+    void main()\n
+    {\n
+      mediump vec4 vertexPosition = vec4(aPosition.x, aPosition.y, 0.0, 1.0);\n
+      vertexPosition = uMvpMatrix * vertexPosition;\n
+      gl_Position = vertexPosition;\n
+      vTexCoord = aTexture;\n
+    }\n
+);
+
+/**
+ * Fragment shader for metaballs
+ */
+const char* const METABALL_FRAG_SHADER = DALI_COMPOSE_SHADER (
+  precision mediump float;\n
+  varying vec2 vTexCoord;\n
+  uniform vec2 uPositionMetaball;\n
+  uniform vec2 uPositionVar;\n
+  uniform vec2 uGravityVector;\n
+  uniform float uRadius;\n
+  uniform float uRadiusVar;\n
+  uniform float uAspect;\n
+  void main()\n
+  {\n
+    vec2 adjustedCoords = vTexCoord * 2.0 - 1.0;\n
+    vec2 finalMetaballPosition = uPositionMetaball + uGravityVector + uPositionVar;\n
+
+    float distance = (adjustedCoords.x - finalMetaballPosition.x) * (adjustedCoords.x - finalMetaballPosition.x) +
+                     (adjustedCoords.y - finalMetaballPosition.y) * (adjustedCoords.y - finalMetaballPosition.y);\n
+    float finalRadius = uRadius + uRadiusVar;\n
+    float color = finalRadius / sqrt( distance );\n
+    vec2 bordercolor = vec2(0.0,0.0);\n
+    if (vTexCoord.x < 0.1)\n
+    {\n
+      bordercolor.x = (0.1 - vTexCoord.x) * 0.8;\n
+    }\n
+    if (vTexCoord.x > 0.9)\n
+    {\n
+      bordercolor.x = (vTexCoord.x - 0.9) * 0.8;\n
+    }\n
+    if (vTexCoord.y < 0.1)\n
+    {\n
+      bordercolor.y = (0.1 - vTexCoord.y) * 0.8;\n
+    }\n
+    if (vTexCoord.y > (0.9 * uAspect))\n
+    {\n
+      bordercolor.y = (vTexCoord.y - (0.9 * uAspect)) * 0.8;\n
+    }\n
+    float border = (bordercolor.x + bordercolor.y) * 0.5;\n
+    gl_FragColor = vec4(color + border,color + border,color + border,1.0);\n
+  }\n
+);
+
+/**
+ * Fragment shader code for metaball and background composition with refraction effect
+ */
+const char* const REFRACTION_FRAG_SHADER = DALI_COMPOSE_SHADER (
+  precision mediump float;\n
+  varying vec2 vTexCoord;\n
+  uniform sampler2D sTexture;\n
+  uniform sampler2D sEffect;\n
+  void main()\n
+  {\n
+    vec4 metaColor = texture2D(sEffect, vTexCoord);\n
+    vec2 zoomCoords;\n
+    float bright = 1.0;\n
+    if (metaColor.r > 0.85)\n
+    {\n
+      zoomCoords = ((vTexCoord - 0.5) * 0.95) + 0.5;\n
+    }\n
+    else if (metaColor.r > 0.78)\n
+    {\n
+      float interpolation = mix(0.95, 1.05, (0.85 - metaColor.r) * 50.0);\n
+      zoomCoords = ((vTexCoord - 0.5) * interpolation) + 0.5;\n
+      bright = 1.2;\n
+    }\n
+    else\n
+    {\n
+      zoomCoords = vTexCoord;\n
+    }\n
+
+    gl_FragColor = texture2D(sTexture, zoomCoords) * bright;\n
+  }\n
+ );
+
+/**
+ * Fragment shader code when there's no effect
+ */
+const char* const FRAG_SHADER = DALI_COMPOSE_SHADER (
+  precision mediump float;\n
+  varying vec2 vTexCoord;\n
+  uniform sampler2D sTexture;\n
+  void main()\n
+  {\n
+    gl_FragColor = texture2D(sTexture, vTexCoord);\n
+  }\n
+);
+
+/**
+ * Metadata for each ball
+ */
+struct MetaballInfo
+{
+  Actor   actor;
+  Vector2 position;
+  float   radius;
+  float   initRadius;
+
+  //Properties needed for animations
+  Property::Index positionIndex;
+  Property::Index positionVarIndex;
+  Property::Index gravityIndex;
+  Property::Index radiusIndex;
+  Property::Index radiusVarIndex;
+  Property::Index aspectIndex;
+};
+
+} // unnamed namespace
+
+/**
+ * Demo using Metaballs
+ *
+ * When the metaball is clicked it starts to grow and fuses into the closest edge of screen
+ */
+class MetaballRefracController : public ConnectionTracker
+{
+public:
+
+  /**
+   * Constructor
+   * @param application
+   */
+  MetaballRefracController( Application& application );
+
+  /**
+   * Destructor
+   */
+  virtual ~MetaballRefracController();
+
+  /**
+   * Creates the metaballs and initializes the scene
+   */
+  void Create( Application& app );
+
+  /**
+   * Touch handler, start the grow animation and creates additional metaballs
+   */
+  bool OnTouch( Actor actor, const TouchData& touch );
+
+  /**
+   * Key event callback to quit the application on escape or back key
+   */
+  void OnKeyEvent( const KeyEvent& event );
+
+private: // Data
+
+  Application&      mApplication;
+  Vector2           mScreenSize;
+
+  Texture           mBackgroundTexture;
+  FrameBuffer       mMetaballFBO;
+  Texture           mMetaballFBOTexture;
+
+  Actor             mMetaballRoot;
+  MetaballInfo      mMetaballs[METABALL_NUMBER];
+
+  Actor             mCompositionActor;
+
+  //Motion
+  Vector2           mCurrentTouchPosition;
+  Vector2           mMetaballPosVariation;
+  Vector2           mMetaballPosVariationFrom;
+  Vector2           mMetaballPosVariationTo;
+  Vector2           mMetaballCenter;
+
+  Vector2           mGravity;
+  Vector2           mGravityVar;
+
+  Renderer          mRendererRefraction;
+  TextureSet        mTextureSetRefraction;
+  Shader            mShaderRefraction;
+  TextureSet        mTextureSetNormal;
+  Shader            mShaderNormal;
+
+  // Animations
+  Animation         mGravityAnimation[METABALL_NUMBER];
+  Animation         mRadiusDecAnimation[METABALL_NUMBER];
+  Animation         mRadiusIncFastAnimation[METABALL_NUMBER];
+  Animation         mRadiusIncSlowAnimation[METABALL_NUMBER];
+  Animation         mRadiusVarAnimation[METABALL_NUMBER];
+  Animation         mPositionVarAnimation[METABALL_NUMBER];
+
+  // Private Helper functions
+
+  /**
+   * Create a mesh data with the geometry for the metaball rendering
+   * @param aspectMappedTexture whether texture coords should be mapped based on aspect ratio
+   */
+  Geometry CreateGeometry( bool aspectMappedTexture = true );
+
+  /**
+   * Create a actor for the metaballs
+   */
+  void CreateMetaballActors();
+
+  /**
+   * Create the render task and FBO to render the metaballs into a texture
+   */
+  void CreateMetaballImage();
+
+  /**
+   * Create the the final composition
+   */
+  void CreateComposition();
+
+  /**
+   * Create all the metaballs animations (gravity, movement, size, etc.)
+   */
+  void CreateAnimations();
+
+  /**
+   * Function to launch the grow slow radius for the metaballs, and also the small variations for metaball[2] and [3]
+   */
+  void LaunchRadiusIncSlowAnimations( Animation& source );
+
+  /**
+   * Function to launch the animation to get the metaball[1] back to the center
+   */
+  void LaunchGetBackToPositionAnimation( Animation& source );
+
+  /**
+   * Function to stop all animations related to the click of the user in the screen
+   */
+  void StopClickAnimations();
+
+  /**
+   * Function to stop all animations related to the after click of the user in the screen
+   */
+  void StopAfterClickAnimations();
+
+  /**
+   * Function that resets the sate of the different Metaballs
+   */
+  void ResetMetaballsState();
+
+  /**
+   * Function to set the actual position of the metaballs when the user clicks the screen
+   */
+  void SetPositionToMetaballs( const Vector2& metaballCenter );
+
+};
+
+/**
+ * Implementation
+ */
+
+MetaballRefracController::MetaballRefracController( Application& application )
+  : mApplication( application )
+{
+  // Connect to the Application's Init signal
+  mApplication.InitSignal().Connect( this, &MetaballRefracController::Create );
+}
+
+MetaballRefracController::~MetaballRefracController()
+{
+  // Nothing to do here;
+}
+
+void MetaballRefracController::Create( Application& app )
+{
+  Stage stage = Stage::GetCurrent();
+
+  stage.KeyEventSignal().Connect( this, &MetaballRefracController::OnKeyEvent );
+
+  mScreenSize = stage.GetSize();
+
+  stage.SetBackgroundColor(Color::BLACK);
+
+  // Load background texture
+  mBackgroundTexture = DemoHelper::LoadTexture( BACKGROUND_IMAGE );
+
+  mGravity = Vector2(GRAVITY_X,GRAVITY_Y);
+  mGravityVar = Vector2(0,0);
+
+  CreateMetaballActors();
+  CreateMetaballImage();
+  CreateComposition();
+  CreateAnimations();
+
+  // Connect the callback to the touch signal on the mesh actor
+  stage.GetRootLayer().TouchSignal().Connect( this, &MetaballRefracController::OnTouch );
+}
+
+Geometry MetaballRefracController::CreateGeometry( bool aspectMappedTexture )
+{
+  const float aspect = mScreenSize.y / mScreenSize.x;
+
+  // Create vertices and specify their color
+  const float xsize = mScreenSize.x * 0.5;
+
+  // Create the meshdata for the metaballs
+  struct VertexPosition { Vector2 position; };
+  struct VertexTexture { Vector2 texture; };
+
+  VertexPosition vertices[] =
+  {
+    { Vector2( -xsize, -xsize * aspect ) },
+    { Vector2(  xsize, -xsize * aspect ) },
+    { Vector2( -xsize,  xsize * aspect ) },
+    { Vector2(  xsize,  xsize * aspect ) }
+  };
+
+  const float textureAspect = (aspectMappedTexture) ? aspect : 1.0f;
+  VertexTexture textures[] =
+  {
+    { Vector2( 0.0f, 0.0f ) },
+    { Vector2( 1.0f, 0.0f ) },
+    { Vector2( 0.0f, 1.0f * textureAspect ) },
+    { Vector2( 1.0f, 1.0f * textureAspect ) }
+  };
+
+  uint32_t numberOfVertices = sizeof(vertices)/sizeof(VertexPosition);
+
+  // Vertices
+  Property::Map positionVertexFormat;
+  positionVertexFormat["aPosition"] = Property::VECTOR2;
+  PropertyBuffer positionVertices = PropertyBuffer::New( positionVertexFormat );
+  positionVertices.SetData( vertices, numberOfVertices );
+
+  // Textures
+  Property::Map textureVertexFormat;
+  textureVertexFormat["aTexture"] = Property::VECTOR2;
+  PropertyBuffer textureVertices = PropertyBuffer::New( textureVertexFormat );
+  textureVertices.SetData( textures, numberOfVertices );
+
+  // Indices
+  const uint16_t indices[] = { 0, 3, 1, 0, 2, 3 };
+
+  // Create the geometry object
+  Geometry texturedQuadGeometry = Geometry::New();
+  texturedQuadGeometry.AddVertexBuffer( positionVertices );
+  texturedQuadGeometry.AddVertexBuffer( textureVertices );
+
+  texturedQuadGeometry.SetIndexBuffer ( &indices[0], sizeof( indices )/ sizeof( indices[0] ) );
+
+  return texturedQuadGeometry;
+}
+
+void MetaballRefracController::CreateMetaballActors()
+{
+  const float aspect = mScreenSize.y / mScreenSize.x;
+
+  // Create the renderer for the metaballs
+  Shader shader = Shader::New( METABALL_VERTEX_SHADER, METABALL_FRAG_SHADER, Shader::Hint::MODIFIES_GEOMETRY );
+  Geometry metaballGeometry = CreateGeometry();
+  Renderer renderer = Renderer::New( metaballGeometry, shader );
+  renderer.SetProperty( Renderer::Property::BLEND_MODE, BlendMode::ON );
+  renderer.SetProperty( Renderer::Property::BLEND_FACTOR_SRC_RGB,    BlendFactor::ONE );
+  renderer.SetProperty( Renderer::Property::BLEND_FACTOR_DEST_RGB,   BlendFactor::ONE );
+  renderer.SetProperty( Renderer::Property::BLEND_FACTOR_SRC_ALPHA,  BlendFactor::ONE );
+  renderer.SetProperty( Renderer::Property::BLEND_FACTOR_DEST_ALPHA, BlendFactor::ONE );
+
+  // Each metaball has a different radius
+  mMetaballs[0].radius = mMetaballs[0].initRadius = 0.0145f;
+  mMetaballs[1].radius = mMetaballs[1].initRadius = 0.012f;
+  mMetaballs[2].radius = mMetaballs[2].initRadius = 0.0135f;
+  mMetaballs[3].radius = mMetaballs[3].initRadius = 0.0135f;
+
+  // Initialization of each of the metaballs
+  for( uint32_t i = 0 ; i < METABALL_NUMBER ; i++ )
+  {
+    mMetaballs[i].position = Vector2(0.0f, 0.0f);
+
+    mMetaballs[i].actor = Actor::New();
+    mMetaballs[i].actor.SetName( "Metaball" );
+    mMetaballs[i].actor.SetScale( 1.0f );
+    mMetaballs[i].actor.SetParentOrigin( ParentOrigin::CENTER );
+
+
+    mMetaballs[i].actor.AddRenderer( renderer );
+
+    mMetaballs[i].positionIndex = mMetaballs[i].actor.RegisterProperty( "uPositionMetaball", mMetaballs[i].position );
+    mMetaballs[i].positionVarIndex = mMetaballs[i].actor.RegisterProperty( "uPositionVar", Vector2(0.f,0.f) );
+    mMetaballs[i].gravityIndex = mMetaballs[i].actor.RegisterProperty( "uGravityVector", Vector2(0.f,0.f) );
+    mMetaballs[i].radiusIndex = mMetaballs[i].actor.RegisterProperty( "uRadius", mMetaballs[i].radius );
+    mMetaballs[i].radiusVarIndex = mMetaballs[i].actor.RegisterProperty( "uRadiusVar", 0.f );
+    mMetaballs[i].aspectIndex = mMetaballs[i].actor.RegisterProperty( "uAspect", aspect );
+  }
+
+  //Root creation
+  mMetaballRoot = Actor::New();
+  mMetaballRoot.SetParentOrigin( ParentOrigin::CENTER );
+  for( uint32_t i = 0 ; i < METABALL_NUMBER ; i++ )
+  {
+    mMetaballRoot.Add( mMetaballs[i].actor );
+  }
+}
+
+void MetaballRefracController::CreateMetaballImage()
+{
+  // Create an FBO and a render task to create to render the metaballs with a fragment shader
+  Stage stage = Stage::GetCurrent();
+  mMetaballFBO = FrameBuffer::New( mScreenSize.x, mScreenSize.y, FrameBuffer::Attachment::NONE );
+  mMetaballFBOTexture = Texture::New( Dali::TextureType::TEXTURE_2D,
+                                      Pixel::RGB888,
+                                      mScreenSize.x, mScreenSize.y );
+  mMetaballFBO.AttachColorTexture( mMetaballFBOTexture );
+
+  stage.Add(mMetaballRoot);
+
+  //Creation of the render task used to render the metaballs
+  RenderTaskList taskList = Stage::GetCurrent().GetRenderTaskList();
+  RenderTask task = taskList.CreateTask();
+  task.SetRefreshRate( RenderTask::REFRESH_ALWAYS );
+  task.SetSourceActor( mMetaballRoot );
+  task.SetExclusive( true );
+  task.SetClearColor( Color::BLACK );
+  task.SetClearEnabled( true );
+  task.SetFrameBuffer( mMetaballFBO );
+}
+
+void MetaballRefracController::CreateComposition()
+{
+  // Create Refraction shader and renderer
+  mShaderRefraction = Shader::New( METABALL_VERTEX_SHADER, REFRACTION_FRAG_SHADER );
+
+  // Create new texture set
+  mTextureSetRefraction = TextureSet::New();
+  mTextureSetRefraction.SetTexture( 0u, mBackgroundTexture  );
+  mTextureSetRefraction.SetTexture( 1u, mMetaballFBOTexture );
+
+  // Create normal shader
+  mShaderNormal = Shader::New( METABALL_VERTEX_SHADER, FRAG_SHADER );
+
+  // Create new texture set
+  mTextureSetNormal = TextureSet::New();
+  mTextureSetNormal.SetTexture( 0u, mBackgroundTexture );
+
+  // Create actor
+  mCompositionActor = Actor::New( );
+  mCompositionActor.SetParentOrigin(ParentOrigin::CENTER);
+  mCompositionActor.SetPosition(Vector3(0.0f, 0.0f, 0.0f));
+  mCompositionActor.SetSize(mScreenSize.x, mScreenSize.y);
+
+  // Create geometry
+  Geometry metaballGeometry = CreateGeometry( false );
+  mRendererRefraction = Renderer::New( metaballGeometry, mShaderNormal );
+  mRendererRefraction.SetTextures( mTextureSetNormal );
+  mCompositionActor.AddRenderer( mRendererRefraction );
+
+  Stage stage = Stage::GetCurrent();
+  stage.Add( mCompositionActor );
+}
+
+void MetaballRefracController::CreateAnimations()
+{
+  uint32_t i = 0;
+  float key;
+
+  mPositionVarAnimation[1] = Animation::New( 2.f );
+  mPositionVarAnimation[1].SetLooping( false );
+  mPositionVarAnimation[1].Pause();
+  mPositionVarAnimation[1].FinishedSignal().Connect( this, &MetaballRefracController::LaunchGetBackToPositionAnimation );
+
+  KeyFrames keySinCosVariation = KeyFrames::New();
+  Vector2 sinCosVariation(0,0);
+  for( i = 0 ; i < 360; i++ )
+  {
+    sinCosVariation.x = 0.05f * ( -sinf(i * Math::PI_OVER_180) + cosf(i * Math::PI_OVER_180) );
+    sinCosVariation.y = 0.05f * ( sinf(i * Math::PI_OVER_180) - cosf(i * Math::PI_OVER_180) );
+    key = i/360.f;
+    keySinCosVariation.Add(key, sinCosVariation);
+  }
+
+  mPositionVarAnimation[2] = Animation::New(6.f);
+  mPositionVarAnimation[2].AnimateBetween(Property( mMetaballs[2].actor, mMetaballs[2].positionVarIndex ), keySinCosVariation);
+  mPositionVarAnimation[2].SetLooping( true );
+  mPositionVarAnimation[2].Pause();
+
+  KeyFrames keyCosSinVariation = KeyFrames::New();
+  Vector2 cosSinVariation(0,0);
+  for( i = 0 ; i < 360; i++ )
+  {
+    cosSinVariation.x = 0.05f * ( -sinf(i * Math::PI_OVER_180) - cosf(i * Math::PI_OVER_180) );
+    cosSinVariation.y = 0.05f * ( sinf(i * Math::PI_OVER_180) + cosf(i * Math::PI_OVER_180) );
+    key = i/360.f;
+    keyCosSinVariation.Add(key, cosSinVariation);
+  }
+
+  mPositionVarAnimation[3] = Animation::New(6.f);
+  mPositionVarAnimation[3].AnimateBetween(Property( mMetaballs[3].actor, mMetaballs[3].positionVarIndex ), keyCosSinVariation);
+  mPositionVarAnimation[3].SetLooping( true );
+  mPositionVarAnimation[3].Pause();
+
+  //Animations for gravity
+  for( i = 0 ; i < METABALL_NUMBER; i++ )
+  {
+    mGravityAnimation[i] = Animation::New( 25.f );
+    mGravityAnimation[i].AnimateBy( Property( mMetaballs[i].actor, mMetaballs[i].gravityIndex ), mGravity * 25.f * 3.f );
+    mGravityAnimation[i].SetLooping( false );
+    mGravityAnimation[i].Pause();
+  }
+
+  //Animation to decrease size of metaballs when there is no click
+  for( i = 0 ; i < METABALL_NUMBER; i++ )
+  {
+    mRadiusDecAnimation[i] = Animation::New( 25.f );
+    mRadiusDecAnimation[i].AnimateBy( Property( mMetaballs[i].actor, mMetaballs[i].radiusIndex ), -0.004f * 25.f * 3.f );
+    mRadiusDecAnimation[i].SetLooping( false );
+    mRadiusDecAnimation[i].Pause();
+  }
+
+  // Animation to grow the size of the metaballs the first second of the click
+  for( i = 0 ; i < METABALL_NUMBER; i++ )
+  {
+    mRadiusIncFastAnimation[i] = Animation::New( 0.3f );
+    mRadiusIncFastAnimation[i].AnimateBy( Property( mMetaballs[i].actor, mMetaballs[i].radiusIndex ), 0.06f );
+    mRadiusIncFastAnimation[i].SetLooping( false );
+    mRadiusIncFastAnimation[i].Pause();
+  }
+  mRadiusIncFastAnimation[0].FinishedSignal().Connect( this, &MetaballRefracController::LaunchRadiusIncSlowAnimations );
+
+  // Animation to grow the size of the metaballs afterwards
+  for( i = 0 ; i < METABALL_NUMBER; i++ )
+  {
+    mRadiusIncSlowAnimation[i] = Animation::New( 20.f );
+    mRadiusIncSlowAnimation[i].AnimateBy( Property( mMetaballs[i].actor, mMetaballs[i].radiusIndex ), 0.04f );
+    mRadiusIncSlowAnimation[i].SetLooping( false );
+    mRadiusIncSlowAnimation[i].Pause();
+  }
+
+  // Keyframes of a sin function
+  KeyFrames keySin = KeyFrames::New();
+  float val;
+  for( i = 0 ; i < 360; i++ )
+  {
+    val = 0.01f * sin(i * Math::PI/180.f);
+    key = i/360.f;
+    keySin.Add(key, val);
+  }
+
+  //Animation to change the size of the metaball
+  mRadiusVarAnimation[2] = Animation::New( 8.f );
+  mRadiusVarAnimation[2].AnimateBetween( Property( mMetaballs[2].actor, mMetaballs[2].radiusVarIndex ), keySin );
+  mRadiusVarAnimation[2].SetLooping( true );
+
+  // Keyframes of a cos function
+  KeyFrames keyCos = KeyFrames::New();
+  for( i = 0 ; i < 360; i++ )
+  {
+    val = 0.01f * cos(i * Math::PI/180.f);
+    key = i/360.f;
+    keyCos.Add(key, val);
+  }
+
+  //Animation to change the size of the metaball
+  mRadiusVarAnimation[3] = Animation::New( 8.f );
+  mRadiusVarAnimation[3].AnimateBetween( Property( mMetaballs[3].actor, mMetaballs[3].radiusVarIndex ), keyCos );
+  mRadiusVarAnimation[3].SetLooping( true );
+}
+
+void MetaballRefracController::LaunchGetBackToPositionAnimation( Animation& source )
+{
+  mMetaballPosVariationTo = Vector2(0,0);
+
+  mPositionVarAnimation[1] = Animation::New( 1.f );
+  mPositionVarAnimation[1].SetLooping( false );
+  mPositionVarAnimation[1].AnimateTo(Property( mMetaballs[1].actor, mMetaballs[1].positionVarIndex ), Vector2(0,0) );
+  mPositionVarAnimation[1].Play();
+}
+
+void MetaballRefracController::LaunchRadiusIncSlowAnimations( Animation& source )
+{
+  for( uint32_t i = 0 ; i < METABALL_NUMBER; i++ )
+  {
+    mRadiusIncSlowAnimation[i].Play();
+  }
+  mPositionVarAnimation[2].Play();
+  mPositionVarAnimation[3].Play();
+}
+
+void MetaballRefracController::StopClickAnimations()
+{
+  for( uint32_t i = 0 ; i < METABALL_NUMBER; i++ )
+  {
+    mRadiusIncSlowAnimation[i].Stop();
+    mRadiusIncFastAnimation[i].Stop();
+  }
+  mPositionVarAnimation[1].Stop();
+  mPositionVarAnimation[2].Stop();
+  mPositionVarAnimation[3].Stop();
+}
+
+void MetaballRefracController::StopAfterClickAnimations()
+{
+  for( uint32_t i = 0 ; i < METABALL_NUMBER; i++ )
+  {
+    mGravityAnimation[i].Stop();
+    mRadiusDecAnimation[i].Stop();
+
+    mMetaballs[i].radius = mMetaballs[i].initRadius;
+
+    mMetaballs[i].actor.SetProperty( mMetaballs[i].gravityIndex, Vector2(0,0) );
+    mMetaballs[i].actor.SetProperty( mMetaballs[i].radiusIndex, mMetaballs[i].radius );
+    mMetaballs[i].actor.SetProperty( mMetaballs[i].radiusVarIndex, 0.f );
+  }
+  mRadiusVarAnimation[2].Stop();
+  mRadiusVarAnimation[3].Stop();
+}
+
+void MetaballRefracController::ResetMetaballsState()
+{
+  mRendererRefraction.SetTextures( mTextureSetNormal );
+  mRendererRefraction.SetShader( mShaderNormal );
+
+  for( uint32_t i = 0 ; i < METABALL_NUMBER; i++ )
+  {
+    mMetaballs[i].radius = mMetaballs[i].initRadius;
+  }
+
+  mMetaballPosVariationTo = Vector2(0,0);
+  mMetaballPosVariationFrom = Vector2(0,0);
+  mMetaballPosVariation = Vector2(0,0);
+  mGravityVar = Vector2(0,0);
+}
+
+void MetaballRefracController::SetPositionToMetaballs( const Vector2& metaballCenter )
+{
+  //We set the position for the metaballs based on click position
+  for( uint32_t i = 0 ; i < METABALL_NUMBER; i++ )
+  {
+    mMetaballs[i].position = metaballCenter;
+    mMetaballs[i].actor.SetProperty( mMetaballs[i].positionIndex, mMetaballs[i].position );
+  }
+}
+
+bool MetaballRefracController::OnTouch( Actor actor, const TouchData& touch )
+{
+  const float aspect = mScreenSize.y / mScreenSize.x;
+  switch( touch.GetState( 0 ) )
+  {
+    case PointState::DOWN:
+    {
+      StopAfterClickAnimations();
+      for( uint32_t i = 0 ; i < METABALL_NUMBER; i++ )
+      {
+        mRadiusIncFastAnimation[i].Play();
+      }
+      mRadiusVarAnimation[2].Play();
+      mRadiusVarAnimation[3].Play();
+
+      //We draw with the refraction-composition shader
+      mRendererRefraction.SetTextures( mTextureSetRefraction );
+      mRendererRefraction.SetShader( mShaderRefraction );
+      mCurrentTouchPosition = touch.GetScreenPosition( 0 );
+
+      //we use the click position for the metaballs
+      Vector2 metaballCenter = Vector2( (mCurrentTouchPosition.x / mScreenSize.x) - 0.5f,
+                                        (aspect * (mScreenSize.y - mCurrentTouchPosition.y) / mScreenSize.y) - 0.5f ) * 2.0f;
+      SetPositionToMetaballs(metaballCenter);
+      break;
+    }
+    case PointState::MOTION:
+    {
+      Vector2 screen = touch.GetScreenPosition( 0 );
+      Vector2 displacement = screen - mCurrentTouchPosition;
+      mCurrentTouchPosition = screen;
+
+      mMetaballPosVariationTo.x += ( displacement.x / mScreenSize.x ) * 2.2f;
+      mMetaballPosVariationTo.y += (-displacement.y / mScreenSize.y ) * 2.2f;
+
+      if (mPositionVarAnimation[1])
+      {
+        mPositionVarAnimation[1].FinishedSignal().Disconnect( this, &MetaballRefracController::LaunchGetBackToPositionAnimation );
+        mPositionVarAnimation[1].Stop();
+      }
+      mPositionVarAnimation[1] = Animation::New( 1.f );
+      mPositionVarAnimation[1].SetLooping( false );
+      mPositionVarAnimation[1].AnimateTo(Property( mMetaballs[1].actor, mMetaballs[1].positionVarIndex ), mMetaballPosVariationTo );
+      mPositionVarAnimation[1].FinishedSignal().Connect( this, &MetaballRefracController::LaunchGetBackToPositionAnimation );
+      mPositionVarAnimation[1].Play();
+
+      //we use the click position for the metaballs
+      Vector2 metaballCenter = Vector2( (screen.x / mScreenSize.x) - 0.5f,
+                                        (aspect * (mScreenSize.y - screen.y) / mScreenSize.y) - 0.5f) * 2.0f;
+      SetPositionToMetaballs(metaballCenter);
+      break;
+    }
+    case PointState::UP:
+    case PointState::LEAVE:
+    case PointState::INTERRUPTED:
+    {
+      //Stop click animations
+      StopClickAnimations();
+
+      //Launch out of screen animations
+      for( uint32_t i = 0 ; i < METABALL_NUMBER; i++ )
+      {
+        mGravityAnimation[i].Play();
+      }
+
+      for( uint32_t i = 0 ; i < METABALL_NUMBER; i++ )
+      {
+        mRadiusDecAnimation[i].Play();
+      }
+      break;
+    }
+    default:
+      break;
+    }
+  return true;
+}
+
+void MetaballRefracController::OnKeyEvent(const KeyEvent& event)
+{
+  if( event.state == KeyEvent::Down )
+  {
+    if( IsKey( event, Dali::DALI_KEY_ESCAPE) || IsKey( event, Dali::DALI_KEY_BACK) )
+    {
+      mApplication.Quit();
+    }
+  }
+}
+
+/**
+ * Main entry point
+ */
+int32_t DALI_EXPORT_API main( int argc, char **argv )
+{
+  Application application = Application::New( &argc, &argv );
+
+  MetaballRefracController test( application );
+  application.MainLoop();
+
+  return 0;
+}
index 54b478d..bab37b3 100755 (executable)
@@ -76,6 +76,12 @@ msgstr "মেশ অঙ্কুৰিত"
 msgid "DALI_DEMO_STR_TITLE_MESH_VISUAL"
 msgstr "3D অনুগামী"
 
+msgid "DALI_DEMO_STR_TITLE_METABALL_EXPLOSION"
+msgstr "মেটাবল মহা-বিস্ফোৰণবাদ"
+
+msgid "DALI_DEMO_STR_TITLE_METABALL_REFRAC"
+msgstr "মেটাবল প্ৰতিসৰিত"
+
 msgid "DALI_DEMO_STR_TITLE_MOTION_BLUR"
 msgstr "অস্পষ্ট"
 
index f0aad71..6190e2a 100755 (executable)
@@ -76,6 +76,12 @@ msgstr "Mesh Veränderung"
 msgid "DALI_DEMO_STR_TITLE_MESH_VISUAL"
 msgstr "3D-Modelle"
 
+msgid "DALI_DEMO_STR_TITLE_METABALL_EXPLOSION"
+msgstr "Metaball Explosion"
+
+msgid "DALI_DEMO_STR_TITLE_METABALL_REFRAC"
+msgstr "Metaball Brechung"
+
 msgid "DALI_DEMO_STR_TITLE_MOTION_BLUR"
 msgstr "Bewegungsunschärfe"
 
index b6339ab..342d10d 100755 (executable)
@@ -112,6 +112,12 @@ msgstr "Mesh Morph"
 msgid "DALI_DEMO_STR_TITLE_MESH_VISUAL"
 msgstr "Mesh Visual"
 
+msgid "DALI_DEMO_STR_TITLE_METABALL_EXPLOSION"
+msgstr "Metaball Explosion"
+
+msgid "DALI_DEMO_STR_TITLE_METABALL_REFRAC"
+msgstr "Metaball Refraction"
+
 msgid "DALI_DEMO_STR_TITLE_MOTION_BLUR"
 msgstr "Motion Blur"
 
index d3d6215..50460ee 100755 (executable)
@@ -115,6 +115,12 @@ msgstr "Mesh Morph"
 msgid "DALI_DEMO_STR_TITLE_MESH_VISUAL"
 msgstr "Mesh Visual"
 
+msgid "DALI_DEMO_STR_TITLE_METABALL_EXPLOSION"
+msgstr "Metaball Explosion"
+
+msgid "DALI_DEMO_STR_TITLE_METABALL_REFRAC"
+msgstr "Metaball Refraction"
+
 msgid "DALI_DEMO_STR_TITLE_MOTION_BLUR"
 msgstr "Motion Blur"
 
index 4d5ae43..6b4458b 100755 (executable)
@@ -76,6 +76,12 @@ msgstr "Transformacion de geometrias"
 msgid "DALI_DEMO_STR_TITLE_MESH_VISUAL"
 msgstr "Gemeotria 3D"
 
+msgid "DALI_DEMO_STR_TITLE_METABALL_EXPLOSION"
+msgstr "Explosion de metabolas"
+
+msgid "DALI_DEMO_STR_TITLE_METABALL_REFRAC"
+msgstr "Refraccion de metabolas"
+
 msgid "DALI_DEMO_STR_TITLE_MOTION_BLUR"
 msgstr "Desenfoque de movimiento"
 
index b56ef25..5e7552e 100755 (executable)
@@ -76,6 +76,12 @@ msgstr "Polygoniverkon Muodonmuutos"
 msgid "DALI_DEMO_STR_TITLE_MESH_VISUAL"
 msgstr "Polygoniverkkovisuaali"
 
+msgid "DALI_DEMO_STR_TITLE_METABALL_EXPLOSION"
+msgstr "Metaball Räjähdys"
+
+msgid "DALI_DEMO_STR_TITLE_METABALL_REFRAC"
+msgstr "Metaball Valon Taittumisella"
+
 msgid "DALI_DEMO_STR_TITLE_MOTION_BLUR"
 msgstr "Liikesumennus"
 
index 0ea0613..51f1239 100755 (executable)
@@ -85,6 +85,12 @@ msgstr "메쉬 형태"
 msgid "DALI_DEMO_STR_TITLE_MESH_VISUAL"
 msgstr "메쉬 비주얼"
 
+msgid "DALI_DEMO_STR_TITLE_METABALL_EXPLOSION"
+msgstr "메타볼 폭발"
+
+msgid "DALI_DEMO_STR_TITLE_METABALL_REFRAC"
+msgstr "메타볼 굴절"
+
 msgid "DALI_DEMO_STR_TITLE_MOTION_BLUR"
 msgstr "모션 블러"
 
index a1f7e83..8873d62 100755 (executable)
@@ -76,6 +76,12 @@ msgstr "മോർഫ് mesh"
 msgid "DALI_DEMO_STR_TITLE_MESH_VISUAL"
 msgstr "3D മോഡലിങ്"
 
+msgid "DALI_DEMO_STR_TITLE_METABALL_EXPLOSION"
+msgstr "മെറ്റാ പന്ത് സ്ഫോടനം"
+
+msgid "DALI_DEMO_STR_TITLE_METABALL_REFRAC"
+msgstr "മെറ്റാ പന്ത് അപവർത്തനം"
+
 msgid "DALI_DEMO_STR_TITLE_MOTION_BLUR"
 msgstr "അവ്യക്തമാക്കല്"
 
index 5b41075..512bd10 100755 (executable)
@@ -79,6 +79,12 @@ msgstr "میش کی تبدیلی"
 msgid "DALI_DEMO_STR_TITLE_MESH_VISUAL"
 msgstr "3D میش"
 
+msgid "DALI_DEMO_STR_TITLE_METABALL_EXPLOSION"
+msgstr "میٹابال دھماکہ"
+
+msgid "DALI_DEMO_STR_TITLE_METABALL_REFRAC"
+msgstr "میٹابال اپورتن"
+
 msgid "DALI_DEMO_STR_TITLE_MOTION_BLUR"
 msgstr "دھندلانے کی حرکت"
 
index f5aafe8..5897486 100755 (executable)
@@ -76,6 +76,12 @@ msgstr "网格变形"
 msgid "DALI_DEMO_STR_TITLE_MESH_VISUAL"
 msgstr "3D模型"
 
+msgid "DALI_DEMO_STR_TITLE_METABALL_EXPLOSION"
+msgstr "元球爆炸"
+
+msgid "DALI_DEMO_STR_TITLE_METABALL_REFRAC"
+msgstr "元球折射"
+
 msgid "DALI_DEMO_STR_TITLE_MOTION_BLUR"
 msgstr "动作模糊"
 
index 92f08e8..e0fcb42 100644 (file)
@@ -73,6 +73,8 @@ extern "C"
 #define DALI_DEMO_STR_TITLE_MAGNIFIER                   dgettext(DALI_DEMO_DOMAIN_LOCAL, "DALI_DEMO_STR_TITLE_MAGNIFIER")
 #define DALI_DEMO_STR_TITLE_MESH_MORPH                  dgettext(DALI_DEMO_DOMAIN_LOCAL, "DALI_DEMO_STR_TITLE_MESH_MORPH")
 #define DALI_DEMO_STR_TITLE_MESH_VISUAL                 dgettext(DALI_DEMO_DOMAIN_LOCAL, "DALI_DEMO_STR_TITLE_MESH_VISUAL")
+#define DALI_DEMO_STR_TITLE_METABALL_EXPLOSION          dgettext(DALI_DEMO_DOMAIN_LOCAL, "DALI_DEMO_STR_TITLE_METABALL_EXPLOSION")
+#define DALI_DEMO_STR_TITLE_METABALL_REFRAC             dgettext(DALI_DEMO_DOMAIN_LOCAL, "DALI_DEMO_STR_TITLE_METABALL_REFRAC")
 #define DALI_DEMO_STR_TITLE_MOTION_BLUR                 dgettext(DALI_DEMO_DOMAIN_LOCAL, "DALI_DEMO_STR_TITLE_MOTION_BLUR")
 #define DALI_DEMO_STR_TITLE_MOTION_STRETCH              dgettext(DALI_DEMO_DOMAIN_LOCAL, "DALI_DEMO_STR_TITLE_MOTION_STRETCH")
 #define DALI_DEMO_STR_TITLE_NATIVE_IMAGE_SOURCE         dgettext(DALI_DEMO_DOMAIN_LOCAL, "DALI_DEMO_STR_TITLE_NATIVE_IMAGE_SOURCE")
@@ -159,6 +161,8 @@ extern "C"
 #define DALI_DEMO_STR_TITLE_MAGNIFIER                   "Magnifier"
 #define DALI_DEMO_STR_TITLE_MESH_MORPH                  "Mesh Morph"
 #define DALI_DEMO_STR_TITLE_MESH_VISUAL                 "Mesh Visual"
+#define DALI_DEMO_STR_TITLE_METABALL_EXPLOSION          "Metaball Explosion"
+#define DALI_DEMO_STR_TITLE_METABALL_REFRAC             "Metaball Refractions"
 #define DALI_DEMO_STR_TITLE_MOTION_BLUR                 "Motion Blur"
 #define DALI_DEMO_STR_TITLE_MOTION_STRETCH              "Motion Stretch"
 #define DALI_DEMO_STR_TITLE_NATIVE_IMAGE_SOURCE         "Native Image Source"