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"