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