diff --git a/com.samsung.dali-demo.xml b/com.samsung.dali-demo.xml
index 43daadd..70a5541 100644
--- a/com.samsung.dali-demo.xml
+++ b/com.samsung.dali-demo.xml
@@ -34,9 +34,15 @@
-
-
-
+
+
+
+
+
+
+
+
+
diff --git a/demo/dali-demo.cpp b/demo/dali-demo.cpp
index 05aa4c3..5ca4f65 100644
--- a/demo/dali-demo.cpp
+++ b/demo/dali-demo.cpp
@@ -63,6 +63,8 @@ int main(int argc, char **argv)
demo.AddExample(Example("logging.example", DALI_DEMO_STR_TITLE_LOGGING));
demo.AddExample(Example("mesh-morph.example", DALI_DEMO_STR_TITLE_MESH_MORPH));
demo.AddExample(Example("mesh-sorting.example", DALI_DEMO_STR_TITLE_MESH_SORTING));
+ 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("textured-mesh.example", DALI_DEMO_STR_TITLE_TEXTURED_MESH));
demo.AddExample(Example("line-mesh.example", DALI_DEMO_STR_TITLE_LINE_MESH));
demo.AddExample(Example("gradients.example", DALI_DEMO_STR_TITLE_COLOR_GRADIENT));
diff --git a/examples/metaball-explosion/metaball-explosion-example.cpp b/examples/metaball-explosion/metaball-explosion-example.cpp
new file mode 100644
index 0000000..1c76add
--- /dev/null
+++ b/examples/metaball-explosion/metaball-explosion-example.cpp
@@ -0,0 +1,763 @@
+/*
+ * Copyright (c) 2014 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
+#include
+
+//Internal includes
+#include
+#include
+#include
+
+#include "shared/view.h"
+
+using namespace Dali;
+using namespace Dali::Toolkit;
+
+namespace
+{
+const char * const BACKGROUND_IMAGE( DALI_IMAGE_DIR "background-2.jpg" );
+const char * const TOOLBAR_IMAGE( DALI_IMAGE_DIR "top-bar.png" );
+
+const float GRAVITY_X(0);
+const float GRAVITY_Y(-0.09);
+}
+
+#define METABALL_NUMBER 12
+
+
+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
+);
+
+
+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
+);
+
+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
+ );
+
+const char*const FRAG_SHADER = DALI_COMPOSE_SHADER (
+ precision mediump float;\n
+ void main()\n
+ {\n
+ gl_FragColor = texture2D(sTexture, vTexCoord);\n
+ }\n
+);
+
+
+struct MetaballInfo
+{
+ Actor actor;
+ Vector2 position;
+ float radius;
+ float initRadius;
+
+ //new shader stuff
+ Property::Index positionIndex;
+ Property::Index positionVarIndex;
+};
+
+
+/**************************************************************************/
+/* Demo using Metaballs ***********/
+/* When the metaball is clicked it explodes in different balls ***********/
+/**************************************************************************/
+class MetaballExplosionController : public ConnectionTracker
+{
+public:
+ MetaballExplosionController( Application& application );
+ ~MetaballExplosionController();
+
+ /**
+ * Main create function, it creates the metaballs and all the related data
+ */
+ void Create( Application& app );
+
+ /**
+ * Touch event function
+ */
+ bool OnTouch( Actor actor, const TouchEvent& touch );
+
+ /**
+ * Key event function
+ */
+ void OnKeyEvent(const KeyEvent& event);
+
+
+private:
+ Application& mApplication;
+ Vector2 mScreenSize;
+
+ Layer mContentLayer;
+
+ Image mBackImage;
+ FrameBufferImage mMetaballFBO;
+
+ 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];
+
+ int mDispersion;
+ Animation mDispersionAnimation[METABALL_NUMBER];
+
+ Timer mTimerDispersion;
+
+ float mTimeMult;
+
+ //Private functions
+
+ /**
+ * Create a mesh data with the geometry for the metaball rendering
+ */
+ Geometry CreateGeometry();
+
+ /**
+ * Create a mesh data with the geometry for the final composition
+ */
+ Geometry CreateGeometryComposition();
+
+ /**
+ * Create a mesh actor for the metaballs
+ */
+ void CreateMetaballActors();
+
+ /**
+ * Create the render task and FBO to render the metaballs into a texture
+ */
+ void CreateMetaballImage();
+
+ /**
+ * Create a mesh image to render the final composition
+ */
+ void AddRefractionImage();
+
+ /**
+ * 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(int 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(Vector2 & metaballCenter);
+};
+
+
+//-----------------------------------------------------------------------------------------------
+//
+// IMPLEMENTATION
+//
+//----------------
+
+MetaballExplosionController::MetaballExplosionController( Application& application )
+ : mApplication( application )
+{
+ // 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();
+
+ mTimeMult = 1.0f;
+
+ stage.SetBackgroundColor(Color::BLACK);
+
+ //Set background image for the view
+ mBackImage = ResourceImage::New( BACKGROUND_IMAGE );
+
+ srand((unsigned)time(0));
+
+ //Create internal data
+ CreateMetaballActors();
+ CreateMetaballImage();
+ AddRefractionImage();
+
+ 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().TouchedSignal().Connect( this, &MetaballExplosionController::OnTouch );
+}
+
+Geometry MetaballExplosionController::CreateGeometry()
+{
+ float aspect = (float)mScreenSize.y / (float)mScreenSize.x;
+
+ // Create vertices and specify their color
+ float xsize = mScreenSize.x * 0.5;
+
+ //We create the meshdata for the metaballs
+ struct VertexPosition { Vector2 position; };
+ struct VertexTexture { Vector2 texture; };
+ struct VertexNormal { Vector3 normal; };
+
+ VertexPosition vertices[] = {
+ { Vector2( -xsize, -xsize * aspect) },
+ { Vector2( xsize, -xsize * aspect) },
+ { Vector2( -xsize, xsize * aspect) },
+ { Vector2( xsize, xsize * aspect) }
+ };
+
+ VertexTexture textures[] = {
+ { Vector2(0.0f, 0.0f) },
+ { Vector2(1.0f, 0.0f) },
+ { Vector2(0.0f, 1.0f * aspect) },
+ { Vector2(1.0f, 1.0f * aspect) }
+ };
+
+ int indices[] = { 0, 3, 1, 0, 2, 3 };
+
+ unsigned int numberOfVertices = sizeof(vertices)/sizeof(VertexPosition);
+
+ //Vertices
+ Property::Map positionVertexFormat;
+ positionVertexFormat["aPosition"] = Property::VECTOR2;
+ PropertyBuffer positionVertices = PropertyBuffer::New( positionVertexFormat, numberOfVertices );
+ positionVertices.SetData(vertices);
+
+ //Textures
+ Property::Map textureVertexFormat;
+ textureVertexFormat["aTexture"] = Property::VECTOR2;
+ PropertyBuffer textureVertices = PropertyBuffer::New( textureVertexFormat, numberOfVertices );
+ textureVertices.SetData(textures);
+
+ //Indices
+ Property::Map indicesVertexFormat;
+ indicesVertexFormat["aIndices"] = Property::INTEGER;
+ PropertyBuffer indicesToVertices = PropertyBuffer::New( indicesVertexFormat, 6 );
+ indicesToVertices.SetData(indices);
+
+ // Create the geometry object
+ Geometry texturedQuadGeometry = Geometry::New();
+ texturedQuadGeometry.AddVertexBuffer( positionVertices );
+ texturedQuadGeometry.AddVertexBuffer( textureVertices );
+
+ texturedQuadGeometry.SetIndexBuffer ( indicesToVertices );
+
+ return texturedQuadGeometry;
+}
+
+Geometry MetaballExplosionController::CreateGeometryComposition()
+{
+ float aspect = (float)mScreenSize.y / (float)mScreenSize.x;
+
+ // Create vertices and specify their color
+ float xsize = mScreenSize.x * 0.5;
+
+ //We create the meshdata for the metaballs
+ struct VertexPosition { Vector2 position; };
+ struct VertexTexture { Vector2 texture; };
+ struct VertexNormal { Vector3 normal; };
+
+ VertexPosition vertices[] = {
+ { Vector2( -xsize, -xsize * aspect) },
+ { Vector2( xsize, -xsize * aspect) },
+ { Vector2( -xsize, xsize * aspect) },
+ { Vector2( xsize, xsize * aspect) }
+ };
+
+ VertexTexture textures[] = {
+ { Vector2(0.0f, 0.0f) },
+ { Vector2(1.0f, 0.0f) },
+ { Vector2(0.0f, 1.0f) },
+ { Vector2(1.0f, 1.0f) }
+ };
+
+ int indices[] = { 0, 3, 1, 0, 2, 3 };
+
+ unsigned int numberOfVertices = sizeof(vertices)/sizeof(VertexPosition);
+
+ //Vertices
+ Property::Map positionVertexFormat;
+ positionVertexFormat["aPosition"] = Property::VECTOR2;
+ PropertyBuffer positionVertices = PropertyBuffer::New( positionVertexFormat, numberOfVertices );
+ positionVertices.SetData(vertices);
+
+ //Textures
+ Property::Map textureVertexFormat;
+ textureVertexFormat["aTexture"] = Property::VECTOR2;
+ PropertyBuffer textureVertices = PropertyBuffer::New( textureVertexFormat, numberOfVertices );
+ textureVertices.SetData(textures);
+
+ //Indices
+ Property::Map indicesVertexFormat;
+ indicesVertexFormat["aIndices"] = Property::INTEGER;
+ PropertyBuffer indicesToVertices = PropertyBuffer::New( indicesVertexFormat, 6 );
+ indicesToVertices.SetData(indices);
+
+ // Create the geometry object
+ Geometry texturedQuadGeometry = Geometry::New();
+ texturedQuadGeometry.AddVertexBuffer( positionVertices );
+ texturedQuadGeometry.AddVertexBuffer( textureVertices );
+
+ texturedQuadGeometry.SetIndexBuffer ( indicesToVertices );
+
+ return texturedQuadGeometry;
+}
+
+float randomNumber(float lowest, float highest)
+{
+ float range=(highest-lowest);
+ return lowest+range*rand()/RAND_MAX;
+}
+
+void MetaballExplosionController::CreateMetaballActors()
+{
+ //Create the shader for the metaballs
+ Shader shader = Shader::New( METABALL_VERTEX_SHADER, METABALL_FRAG_SHADER );
+
+ Material material = Material::New( shader );
+ material.SetBlendMode(BlendingMode::ON );
+ material.SetBlendFunc(BlendingFactor::ONE, BlendingFactor::ONE, BlendingFactor::ONE, BlendingFactor::ONE);
+
+ Geometry metaballGeom = CreateGeometry();
+
+ //Initialization of each of the metaballs
+ for( int i = 0; i < METABALL_NUMBER; i++ )
+ {
+ mMetaballs[i].position = Vector2(0.0f, 0.0f);
+ mMetaballs[i].radius = mMetaballs[i].initRadius = randomNumber(0.025f,0.035f);
+
+ mMetaballs[i].actor = Actor::New( );
+ mMetaballs[i].actor.SetName("Metaball");
+ mMetaballs[i].actor.SetScale( 1.0f );
+ mMetaballs[i].actor.SetParentOrigin( ParentOrigin::CENTER );
+
+ Renderer renderer = Renderer::New( metaballGeom, material );
+ 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(randomNumber(-0.2,0.2),randomNumber(-0.2,0.2)) );
+
+ mMetaballs[i].actor.RegisterProperty( "uRadius", mMetaballs[i].radius );
+
+ mMetaballs[i].actor.RegisterProperty( "uRadiusVar", 0.f );
+
+ mMetaballs[i].actor.SetSize(400, 400);
+ }
+
+ //Root creation
+ mMetaballRoot = Actor::New();
+ mMetaballRoot.SetParentOrigin( ParentOrigin::CENTER );
+ for( int i = 0; i < METABALL_NUMBER; i++ )
+ {
+ mMetaballRoot.Add( mMetaballs[i].actor );
+ }
+
+ //Initialization of variables related to metaballs
+ mMetaballPosVariation = Vector2(0,0);
+ mMetaballPosVariationFrom = Vector2(0,0);
+ mMetaballPosVariationTo = Vector2(0,0);
+ mCurrentTouchPosition = Vector2(0,0);
+}
+
+void MetaballExplosionController::CreateMetaballImage()
+{
+ //We create an FBO and a render task to create to render the metaballs with a fragment shader
+ Stage stage = Stage::GetCurrent();
+ mMetaballFBO = FrameBufferImage::New(mScreenSize.x, mScreenSize.y, Pixel::RGBA8888, RenderBuffer::COLOR_DEPTH);
+
+
+ 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.SetTargetFrameBuffer( mMetaballFBO );
+}
+
+void MetaballExplosionController::AddRefractionImage()
+{
+ //Create Gaussian blur for the rendered image
+ FrameBufferImage fbo;
+ fbo = FrameBufferImage::New( mScreenSize.x, mScreenSize.y, Pixel::RGBA8888, RenderBuffer::COLOR_DEPTH);
+
+ GaussianBlurView gbv = GaussianBlurView::New(5, 2.0f, Pixel::RGBA8888, 0.5f, 0.5f, true);
+ gbv.SetBackgroundColor(Color::TRANSPARENT);
+ gbv.SetUserImageAndOutputRenderTarget( mMetaballFBO, fbo );
+ gbv.SetSize(mScreenSize.x, mScreenSize.y);
+ Stage::GetCurrent().Add(gbv);
+ gbv.Activate();
+
+ //Create new shader
+ Shader shader = Shader::New( METABALL_VERTEX_SHADER, REFRACTION_FRAG_SHADER );
+ //Create new material
+ Material material = Material::New( shader );
+
+ //Add Textures
+ material.AddTexture(mBackImage, "sTexture");
+ material.AddTexture(fbo, "sEffect");
+
+ //Create geometry
+ Geometry metaballGeom = CreateGeometryComposition();
+
+ Renderer mRenderer = Renderer::New( metaballGeom, material );
+
+ 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( int i = 0; i < METABALL_NUMBER; i++ )
+ {
+ float key;
+ KeyFrames keySinCosVariation = KeyFrames::New();
+ Vector2 sinCosVariation(0,0);
+
+ direction.x = randomNumber(-100.f,100.f);
+ direction.y = randomNumber(-100.f,100.f);
+
+ direction.Normalize();
+ direction *= 0.1f;
+
+ for( int j = 0; j < 360; j++ )
+ {
+ sinCosVariation.x = sin(j * Math::PI/180.f) * direction.x;
+ sinCosVariation.y = cos(j * Math::PI/180.f) * direction.y;
+ 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( int 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(int ball)
+{
+ Vector2 position;
+ position.x = randomNumber(-1.5f,1.5f);
+ position.y = randomNumber(-1.5f,1.5f);
+
+ mDispersionAnimation[ball] = Animation::New(2.0f * mTimeMult);
+ 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( int i = 0; i < METABALL_NUMBER; i++ )
+ {
+ mDispersionAnimation[i] = Animation::New(1.5f + i*0.25f*mTimeMult);
+ 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(Vector2 & metaballCenter)
+{
+ //We set the position for the metaballs based on click position
+ for( int 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 TouchEvent& touch )
+{
+ const TouchPoint &point = touch.GetPoint(0);
+ float aspectR = mScreenSize.y / mScreenSize.x;
+
+ switch( point.state )
+ {
+ case TouchPoint::Down:
+ {
+ ResetMetaballs(true);
+
+ Vector2 metaballCenter = Vector2((point.screen.x / mScreenSize.x) - 0.5, (aspectR * (mScreenSize.y - point.screen.y) / mScreenSize.y) - 0.5) * 2.0;
+ SetPositionToMetaballs(metaballCenter);
+
+ break;
+ }
+ case TouchPoint::Motion:
+ {
+ Vector2 metaballCenter = Vector2((point.screen.x / mScreenSize.x) - 0.5, (aspectR * (mScreenSize.y - point.screen.y) / mScreenSize.y) - 0.5) * 2.0;
+ SetPositionToMetaballs(metaballCenter);
+ break;
+ }
+ case TouchPoint::Up:
+ case TouchPoint::Leave:
+ case TouchPoint::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 functions
+//
+//-----------------------------------------------------------------------------------------------
+
+void RunTest( Application& application )
+{
+ MetaballExplosionController test( application );
+
+ application.MainLoop();
+}
+
+// Entry point for Linux & Tizen applications
+//
+int main( int argc, char **argv )
+{
+ Application application = Application::New( &argc, &argv );
+
+ RunTest( application );
+
+ return 0;
+}
diff --git a/examples/metaball-refrac/metaball-refrac-example.cpp b/examples/metaball-refrac/metaball-refrac-example.cpp
new file mode 100644
index 0000000..94fd5b6
--- /dev/null
+++ b/examples/metaball-refrac/metaball-refrac-example.cpp
@@ -0,0 +1,878 @@
+/*
+ * Copyright (c) 2014 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.
+ *
+ */
+
+#include
+#include
+#include
+
+#include
+#include
+
+using namespace Dali;
+using namespace Dali::Toolkit;
+
+namespace
+{
+const char * const BACKGROUND_IMAGE( DALI_IMAGE_DIR "background-2.jpg" );
+const char * const TOOLBAR_IMAGE( DALI_IMAGE_DIR "top-bar.png" );
+
+const float GRAVITY_X(0);
+const float GRAVITY_Y(-0.09);
+}
+
+#define METABALL_NUMBER 4
+
+const char*const METABALL_VERTEX_SHADER = DALI_COMPOSE_SHADER (
+ attribute mediump vec2 aPosition;\n
+ attribute mediump vec2 aTexture;\n
+ attribute mediump vec3 aNormal;\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
+);
+
+
+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
+);
+
+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.81)\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
+ );
+
+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
+);
+
+
+struct MetaballInfo
+{
+ //ShaderEffect shader;
+ 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;
+};
+
+
+/***************************************************************************/
+/* Demo using Metaballs for Refraction when clicking the screen ************/
+/* The concept is similar to the Note 5 ScreenLock ************/
+/***************************************************************************/
+class MetaballRefracController : public ConnectionTracker
+{
+public:
+ MetaballRefracController( Application& application );
+ ~MetaballRefracController();
+
+ void Create( Application& app );
+ bool OnTouch( Actor actor, const TouchEvent& touch );
+ void OnKeyEvent(const KeyEvent& event);
+
+ void SetGravity(const Vector2 & gravity);
+
+
+private:
+ Application& mApplication;
+ Vector2 mScreenSize;
+
+ Layer mContentLayer;
+
+ Image mBackImage;
+ FrameBufferImage mMetaballFBO;
+
+ Actor mMetaballRoot;
+ MetaballInfo mMetaballs[METABALL_NUMBER];
+
+ Actor mCompositionActor;
+
+ //Motion
+ bool mExitClick;
+ Vector2 mCurrentTouchPosition;
+ Vector2 mMetaballPosVariation;
+ Vector2 mMetaballPosVariationFrom;
+ Vector2 mMetaballPosVariationTo;
+ Vector2 mMetaballCenter;
+
+ Vector2 mGravity;
+ Vector2 mGravityVar;
+
+ Renderer mRendererRefraction;
+ Material mMaterialRefraction;
+ Material mMaterialNormal;
+
+ //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 functions
+ Geometry CreateGeometry();
+ Geometry CreateGeometryComposition();
+
+ void CreateMetaballActors();
+ void CreateMetaballImage();
+ void AddRefractionImage();
+ void CreateAnimations();
+
+ void LaunchRadiusIncSlowAnimations(Animation &source);
+ void LaunchGetBackToPositionAnimation(Animation &source);
+
+ void StopClickAnimations();
+ void StopAfterClickAnimations();
+
+ void ResetMetaballsState();
+
+ void SetPositionToMetaballs(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;
+}
+
+/*
+ * Setter function for gravity
+ */
+void MetaballRefracController::SetGravity(const Vector2 & gravity)
+{
+ mGravity = gravity;
+}
+
+/**
+ * Main create function, it creates the metaballs and all the
+ */
+void MetaballRefracController::Create( Application& app )
+{
+ Stage stage = Stage::GetCurrent();
+
+ stage.KeyEventSignal().Connect(this, &MetaballRefracController::OnKeyEvent);
+
+ mScreenSize = stage.GetSize();
+
+ stage.SetBackgroundColor(Color::BLACK);
+
+ //Set background image for the view
+ mBackImage = ResourceImage::New( BACKGROUND_IMAGE );
+
+ mGravity = Vector2(GRAVITY_X,GRAVITY_Y);
+ mGravityVar = Vector2(0,0);
+
+ //Create internal data
+ CreateMetaballActors();
+ CreateMetaballImage();
+ AddRefractionImage();
+
+ CreateAnimations();
+
+ // Connect the callback to the touch signal on the mesh actor
+ stage.GetRootLayer().TouchedSignal().Connect( this, &MetaballRefracController::OnTouch );
+}
+
+/**
+ * Create a mesh data with the geometry for the metaball rendering
+ */
+Geometry MetaballRefracController::CreateGeometry()
+{
+ float aspect = (float)mScreenSize.y / (float)mScreenSize.x;
+
+ // Create vertices and specify their color
+ float xsize = mScreenSize.x * 0.5;
+
+ //We create the meshdata for the metaballs
+ struct VertexPosition { Vector2 position; };
+ struct VertexTexture { Vector2 texture; };
+ struct VertexNormal { Vector3 normal; };
+
+ VertexPosition vertices[] = {
+ { Vector2( -xsize, -xsize * aspect) },
+ { Vector2( xsize, -xsize * aspect) },
+ { Vector2( -xsize, xsize * aspect) },
+ { Vector2( xsize, xsize * aspect) }
+ };
+
+ VertexTexture textures[] = {
+ { Vector2(0.0f, 0.0f) },
+ { Vector2(1.0f, 0.0f) },
+ { Vector2(0.0f, 1.0f * aspect) },
+ { Vector2(1.0f, 1.0f * aspect) }
+ };
+
+ VertexNormal normals [] = {
+ { Vector3(0.0f, 0.0f, 1.0f) },
+ { Vector3(0.0f, 0.0f, 1.0f) },
+ { Vector3(0.0f, 0.0f, 1.0f) },
+ { Vector3(0.0f, 0.0f, 1.0f) }
+ };
+
+ int indices[] = { 0, 3, 1, 0, 2, 3 };
+
+ unsigned int numberOfVertices = sizeof(vertices)/sizeof(VertexPosition);
+
+ //Vertices
+ Property::Map positionVertexFormat;
+ positionVertexFormat["aPosition"] = Property::VECTOR2;
+ PropertyBuffer positionVertices = PropertyBuffer::New( positionVertexFormat, numberOfVertices );
+ positionVertices.SetData(vertices);
+
+ //Textures
+ Property::Map textureVertexFormat;
+ textureVertexFormat["aTexture"] = Property::VECTOR2;
+ PropertyBuffer textureVertices = PropertyBuffer::New( textureVertexFormat, numberOfVertices );
+ textureVertices.SetData(textures);
+
+ //Normals
+ Property::Map normalVertexFormat;
+ normalVertexFormat["aNormal"] = Property::VECTOR3;
+ PropertyBuffer normalVertices = PropertyBuffer::New( normalVertexFormat, numberOfVertices );
+ normalVertices.SetData(normals);
+
+ //Indices
+ Property::Map indicesVertexFormat;
+ indicesVertexFormat["aIndices"] = Property::INTEGER;
+ PropertyBuffer indicesToVertices = PropertyBuffer::New( indicesVertexFormat, 6 );
+ indicesToVertices.SetData(indices);
+
+
+ // Create the geometry object
+ Geometry texturedQuadGeometry = Geometry::New();
+ texturedQuadGeometry.AddVertexBuffer( positionVertices );
+ texturedQuadGeometry.AddVertexBuffer( textureVertices );
+ texturedQuadGeometry.AddVertexBuffer( normalVertices );
+
+ texturedQuadGeometry.SetIndexBuffer ( indicesToVertices );
+
+ return texturedQuadGeometry;
+}
+
+/**
+ * Create a mesh data with the geometry for the metaball rendering
+ */
+Geometry MetaballRefracController::CreateGeometryComposition()
+{
+ float aspect = (float)mScreenSize.y / (float)mScreenSize.x;
+
+ // Create vertices and specify their color
+ float xsize = mScreenSize.x * 0.5;
+
+ //We create the meshdata for the metaballs
+ struct VertexPosition { Vector2 position; };
+ struct VertexTexture { Vector2 texture; };
+ struct VertexNormal { Vector3 normal; };
+
+ VertexPosition vertices[] = {
+ { Vector2( -xsize, -xsize * aspect) },
+ { Vector2( xsize, -xsize * aspect) },
+ { Vector2( -xsize, xsize * aspect) },
+ { Vector2( xsize, xsize * aspect) }
+ };
+
+ VertexTexture textures[] = {
+ { Vector2(0.0f, 0.0f) },
+ { Vector2(1.0f, 0.0f) },
+ { Vector2(0.0f, 1.0f) },
+ { Vector2(1.0f, 1.0f) }
+ };
+
+ VertexNormal normals [] = {
+ { Vector3(0.0f, 0.0f, 1.0f) },
+ { Vector3(0.0f, 0.0f, 1.0f) },
+ { Vector3(0.0f, 0.0f, 1.0f) },
+ { Vector3(0.0f, 0.0f, 1.0f) }
+ };
+
+ int indices[] = { 0, 3, 1, 0, 2, 3 };
+
+ unsigned int numberOfVertices = sizeof(vertices)/sizeof(VertexPosition);
+
+ //Vertices
+ Property::Map positionVertexFormat;
+ positionVertexFormat["aPosition"] = Property::VECTOR2;
+ PropertyBuffer positionVertices = PropertyBuffer::New( positionVertexFormat, numberOfVertices );
+ positionVertices.SetData(vertices);
+
+ //Textures
+ Property::Map textureVertexFormat;
+ textureVertexFormat["aTexture"] = Property::VECTOR2;
+ PropertyBuffer textureVertices = PropertyBuffer::New( textureVertexFormat, numberOfVertices );
+ textureVertices.SetData(textures);
+
+ //Normals
+ Property::Map normalVertexFormat;
+ normalVertexFormat["aNormal"] = Property::VECTOR3;
+ PropertyBuffer normalVertices = PropertyBuffer::New( normalVertexFormat, numberOfVertices );
+ normalVertices.SetData(normals);
+
+ //Indices
+ Property::Map indicesVertexFormat;
+ indicesVertexFormat["aIndices"] = Property::INTEGER;
+ PropertyBuffer indicesToVertices = PropertyBuffer::New( indicesVertexFormat, 6 );
+ indicesToVertices.SetData(indices);
+
+
+ // Create the geometry object
+ Geometry texturedQuadGeometry = Geometry::New();
+ texturedQuadGeometry.AddVertexBuffer( positionVertices );
+ texturedQuadGeometry.AddVertexBuffer( textureVertices );
+ texturedQuadGeometry.AddVertexBuffer( normalVertices );
+
+ texturedQuadGeometry.SetIndexBuffer ( indicesToVertices );
+
+ return texturedQuadGeometry;
+}
+
+/**
+ * Create a mesh actor for the metaballs
+ */
+void MetaballRefracController::CreateMetaballActors()
+{
+ //We create metaball structures
+ //With MeshData Textured
+ float aspect = (float)mScreenSize.y / (float)mScreenSize.x;
+
+ //Create the shader for the metaballs
+
+ Shader shader = Shader::New( METABALL_VERTEX_SHADER, METABALL_FRAG_SHADER );
+
+ Material material = Material::New( shader );
+ material.SetBlendMode(BlendingMode::ON );
+ material.SetBlendFunc(BlendingFactor::ONE, BlendingFactor::ONE, BlendingFactor::ONE, BlendingFactor::ONE);
+
+ Geometry metaballGeom = CreateGeometry();
+
+ //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 (int 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 );
+
+ Renderer renderer = Renderer::New( metaballGeom, material );
+ 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 );
+
+ mMetaballs[i].actor.SetSize(400, 400);
+ }
+
+ //Root creation
+ mMetaballRoot = Actor::New();
+ mMetaballRoot.SetParentOrigin( ParentOrigin::CENTER );
+ for (int i = 0 ; i < METABALL_NUMBER ; i++)
+ {
+ mMetaballRoot.Add( mMetaballs[i].actor );
+ }
+
+ //Initialization of variables related to metaballs
+ mMetaballPosVariation = Vector2(0,0);
+ mMetaballPosVariationFrom = Vector2(0,0);
+ mMetaballPosVariationTo = Vector2(0,0);
+ mCurrentTouchPosition = Vector2(0,0);
+}
+
+/**
+ * Create the render task and FBO to render the metaballs into a texture
+ */
+void MetaballRefracController::CreateMetaballImage()
+{
+ //We create an FBO and a render task to create to render the metaballs with a fragment shader
+ Stage stage = Stage::GetCurrent();
+ mMetaballFBO = FrameBufferImage::New(mScreenSize.x, mScreenSize.y );
+
+ 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.SetTargetFrameBuffer( mMetaballFBO );
+}
+
+/**
+ * Create a mesh image to render the final composition
+ */
+void MetaballRefracController::AddRefractionImage()
+{
+ //Creation of the composition image
+
+ //Create geometry
+ Geometry metaballGeom = CreateGeometryComposition();
+
+ //Create Refraction shader and renderer
+ Shader shader = Shader::New( METABALL_VERTEX_SHADER, REFRACTION_FRAG_SHADER );
+ //Create new material
+ mMaterialRefraction = Material::New( shader );
+
+ //Add Textures
+ mMaterialRefraction.AddTexture(mBackImage, "sTexture");
+ mMaterialRefraction.AddTexture(mMetaballFBO, "sEffect");
+
+ //Create normal shader
+ Shader shaderNormal = Shader::New( METABALL_VERTEX_SHADER, FRAG_SHADER );
+ //Create new material
+ mMaterialNormal = Material::New( shaderNormal );
+
+ //Add samplers
+ mMaterialNormal.AddTexture(mBackImage, "sTexture");
+
+
+ //Create actor
+ mCompositionActor = Actor::New( );
+ mCompositionActor.SetParentOrigin(ParentOrigin::CENTER);
+ mCompositionActor.SetPosition(Vector3(0.0f, 0.0f, 0.0f));
+ mCompositionActor.SetSize(mScreenSize.x, mScreenSize.y);
+
+
+ mRendererRefraction = Renderer::New( metaballGeom, mMaterialNormal );
+ mCompositionActor.AddRenderer( mRendererRefraction );
+
+ Stage stage = Stage::GetCurrent();
+ stage.Add( mCompositionActor );
+}
+
+/**
+ * Creation of all the metaballs animations (gravity, movement, size, etc.)
+ */
+void MetaballRefracController::CreateAnimations()
+{
+ int 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 * (-sin(i * Math::PI/180.f) + cos(i * Math::PI/180.f));
+ sinCosVariation.y = 0.05f * (sin(i * Math::PI/180.f) - cos(i * Math::PI/180.f));
+ 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 * (-sin(i * Math::PI/180.f) - cos(i * Math::PI/180.f));
+ cosSinVariation.y = 0.05f * (sin(i * Math::PI/180.f) + cos(i * Math::PI/180.f));
+ 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 );
+}
+
+/**
+ * Function to launch the animation to get the metaball[1] back to the center
+ */
+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();
+}
+
+/**
+ * Function to launch the gro slow radius for the metaballs, and also the small variations for metaball[2] and [3]
+ */
+void MetaballRefracController::LaunchRadiusIncSlowAnimations(Animation &source)
+{
+ for (int i = 0 ; i < METABALL_NUMBER ; i++)
+ {
+ mRadiusIncSlowAnimation[i].Play();
+ }
+ mPositionVarAnimation[2].Play();
+ mPositionVarAnimation[3].Play();
+}
+
+/**
+ * Function to stop all animations related to the click of the user in the screen
+ */
+void MetaballRefracController::StopClickAnimations()
+{
+ for (int i = 0 ; i < METABALL_NUMBER ; i++)
+ {
+ mRadiusIncSlowAnimation[i].Stop();
+ mRadiusIncFastAnimation[i].Stop();
+ }
+ mPositionVarAnimation[1].Stop();
+ mPositionVarAnimation[2].Stop();
+ mPositionVarAnimation[3].Stop();
+}
+
+/**
+ * Function to stop all animations related to the after click of the user in the screen
+ */
+void MetaballRefracController::StopAfterClickAnimations()
+{
+ for (int 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();
+}
+
+/*
+ * Function that resets the sate of the different Metaballs
+ */
+void MetaballRefracController::ResetMetaballsState()
+{
+ mRendererRefraction.SetMaterial(mMaterialNormal);
+
+ for (int 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);
+}
+
+/**
+ * Function to set the actual position of the metaballs when the user clicks the screen
+ */
+void MetaballRefracController::SetPositionToMetaballs(Vector2 & metaballCenter)
+{
+ //We set the position for the metaballs based on click position
+ for (int i = 0 ; i < METABALL_NUMBER ; i++)
+ {
+ mMetaballs[i].position = metaballCenter;
+ mMetaballs[i].actor.SetProperty(mMetaballs[i].positionIndex, mMetaballs[0].position); // 0 y no i ?!?!?!
+ }
+}
+
+bool MetaballRefracController::OnTouch( Actor actor, const TouchEvent& touch )
+{
+ const TouchPoint &point = touch.GetPoint(0);
+ float aspectR = mScreenSize.y / mScreenSize.x;
+ switch(point.state)
+ {
+ case TouchPoint::Down:
+ {
+ StopAfterClickAnimations();
+ for (int i = 0 ; i < METABALL_NUMBER ; i++)
+ mRadiusIncFastAnimation[i].Play();
+ mRadiusVarAnimation[2].Play();
+ mRadiusVarAnimation[3].Play();
+
+ //We draw with the refraction-composition shader
+ mRendererRefraction.SetMaterial(mMaterialRefraction);
+
+ mCurrentTouchPosition = point.screen;
+
+ //we use the click position for the metaballs
+ Vector2 metaballCenter = Vector2((point.screen.x / mScreenSize.x) - 0.5, (aspectR * (mScreenSize.y - point.screen.y) / mScreenSize.y) - 0.5) * 2.0;
+ SetPositionToMetaballs(metaballCenter);
+ break;
+ }
+ case TouchPoint::Motion:
+ {
+ Vector2 displacement = point.screen - mCurrentTouchPosition;
+ mCurrentTouchPosition = point.screen;
+
+ mMetaballPosVariationTo.x += (displacement.x / mScreenSize.x) * 2.2;
+ mMetaballPosVariationTo.y += (- displacement.y / mScreenSize.y) * 2.2;
+
+ 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((point.screen.x / mScreenSize.x) - 0.5, (aspectR * (mScreenSize.y - point.screen.y) / mScreenSize.y) - 0.5) * 2.0;
+ SetPositionToMetaballs(metaballCenter);
+ break;
+ }
+ case TouchPoint::Up:
+ case TouchPoint::Leave:
+ case TouchPoint::Interrupted:
+ {
+ //Stop click animations
+ StopClickAnimations();
+
+ //Launch out of screen animations
+ for (int i = 0 ; i < METABALL_NUMBER ; i++)
+ mGravityAnimation[i].Play();
+
+ for (int 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();
+ }
+ }
+}
+
+
+//
+//
+//-----------------------------------------------------------------------------------------------
+
+void RunTest( Application& application )
+{
+ MetaballRefracController test( application );
+
+ application.MainLoop();
+}
+
+// Entry point for Linux & Tizen applications
+//
+int main( int argc, char **argv )
+{
+ Application application = Application::New( &argc, &argv );
+
+ RunTest( application );
+
+ return 0;
+}
+
diff --git a/shared/dali-demo-strings.h b/shared/dali-demo-strings.h
index b2b10d9..0e8f240 100644
--- a/shared/dali-demo-strings.h
+++ b/shared/dali-demo-strings.h
@@ -91,6 +91,8 @@ extern "C"
#define DALI_DEMO_STR_TITLE_LOGGING "Logging"
#define DALI_DEMO_STR_TITLE_MESH_MORPH "Mesh Morph"
#define DALI_DEMO_STR_TITLE_MESH_SORTING "Mesh Sorting"
+#define DALI_DEMO_STR_TITLE_METABALL_EXPLOSION "Metaball Explosion"
+#define DALI_DEMO_STR_TITLE_METABALL_REFRAC "Metaball Refractions"
#define DALI_DEMO_STR_TITLE_TEXTURED_MESH "Mesh Texture"
#define DALI_DEMO_STR_TITLE_LINE_MESH "Mesh Line"
#define DALI_DEMO_STR_TITLE_COLOR_GRADIENT "Color Gradient"