#include <dali-toolkit/internal/controls/scrollable/bouncing-effect-actor.h>
// EXTERNAL INCLUDES
-#include <math.h>
-#include <dali/public-api/animation/constraint.h>
-#include <dali/public-api/shader-effects/shader-effect.h>
+#include <dali/public-api/actors/renderer.h>
+#include <dali/public-api/geometry/geometry.h>
#include <dali/public-api/math/vector3.h>
+#include <dali/public-api/object/property-buffer.h>
+#include <dali/public-api/object/property-map.h>
+#include <dali/public-api/shader-effects/material.h>
+#include <dali/public-api/shader-effects/shader.h>
namespace Dali
{
namespace
{
// Bouncing effect is presented by stacked three layers with same color and opacity
-const size_t NUM_LAYERS( 3 );
const Vector3 LAYER_HEIGHTS( 1.f, 27.f/42.f, 13.f/42.f);
-/*
-// use the actor color to paint every layer
-const char* MESH_FRAGMENT_SHADER =
-"void main()\n"
-"{\n"
-" gl_FragColor = uColor;\n"
-"}\n";
-*/
-// Constraint to move the vertices vertically
-struct VertexPositionConstraint
-{
- VertexPositionConstraint( float initialY, float range )
- : mInitialY( initialY ),
- mRange( range )
- {
- }
- void operator()( Vector3& current, const PropertyInputContainer& inputs )
- {
- current.y = mInitialY + mRange * fabsf( inputs[0]->GetFloat() );
- }
+#define MAKE_SHADER(A)#A
+
+// Modify the vertex position according to the bounce coefficient;
+const char* MESH_VERTEX_SHADER = MAKE_SHADER(
+attribute mediump vec3 aPosition1;\n
+attribute mediump vec3 aPosition2;\n
+uniform mediump mat4 uMvpMatrix;\n
+uniform mediump vec3 uSize;
+uniform mediump float uBounceCoefficient;\n
+\n
+void main()\n
+{\n
+ gl_Position = uMvpMatrix * vec4(mix( aPosition1, aPosition2, abs(uBounceCoefficient) )*uSize, 1.0);\n
+}
+);
- float mInitialY;
- float mRange;
-};
+// use the actor color to paint every layer
+const char* MESH_FRAGMENT_SHADER = MAKE_SHADER(
+uniform lowp vec4 uColor;\n
+void main()\n
+{\n
+ gl_FragColor = uColor;\n
+}\n;
+);
} // namespace Anon
Actor CreateBouncingEffectActor( Property::Index& bouncePropertyIndex )
{
- Actor meshActor;
-/*
- Dali::AnimatableMesh mesh;
- Dali::MeshActor meshActor;
-
- Dali::AnimatableMesh::Faces faces;
- faces.reserve( NUM_LAYERS * 6 ); // 2 triangles per layer
- for( size_t i=0; i<NUM_LAYERS; i++ )
- {
- size_t j=i*4;
- faces.push_back(j); faces.push_back(j+3); faces.push_back(j+1);
- faces.push_back(j); faces.push_back(j+2); faces.push_back(j+3);
- }
-
- mesh = Dali::AnimatableMesh::New(NUM_LAYERS*4, faces); // 4 vertices per layer
- for( size_t i=0;i<NUM_LAYERS;i++ )
- {
- size_t j=i*4;
- float positionZ = 0.01f*static_cast<float>( i ); // the interval between each layer is 0.01
- mesh[j ].SetPosition( Vector3( -0.5f, -0.5f, positionZ ) );
- mesh[j+1].SetPosition( Vector3( 0.5f, -0.5f, positionZ ) );
- mesh[j+2].SetPosition( Vector3( -0.5f, -0.5f, positionZ ) );
- mesh[j+3].SetPosition( Vector3( 0.5f, -0.5f, positionZ ) );
- }
-
- meshActor = Dali::MeshActor::New(mesh);
-
- Dali::ShaderEffect shaderEffect = Dali::ShaderEffect::New( "", MESH_FRAGMENT_SHADER,
- GEOMETRY_TYPE_UNTEXTURED_MESH,
- Dali::ShaderEffect::HINT_BLENDING );
- meshActor.SetShaderEffect(shaderEffect);
-
- // To control the movement of all vertices with one custom property
- bouncePropertyIndex = meshActor.RegisterProperty("BounceCoeffcient", 0.f);
- for( size_t i=0;i<NUM_LAYERS;i++ )
+ // Create the bouncing mesh geometry
+ struct VertexPosition
{
- size_t j=i*4;
- Constraint constraint = Constraint::New<Vector3>( mesh, mesh.GetPropertyIndex(j+2, AnimatableVertex::Property::POSITION ), VertexPositionConstraint(-0.5f, LAYER_HEIGHTS[i]) );
- constraint.AddSource( Source(meshActor, bouncePropertyIndex) );
- constraint.Apply();
-
- constraint = Constraint::New<Vector3>( mesh, mesh.GetPropertyIndex(j+3, AnimatableVertex::Property::POSITION), VertexPositionConstraint(-0.5f, LAYER_HEIGHTS[i]) );
- constraint.AddSource( Source(meshActor, bouncePropertyIndex) );
- constraint.Apply();
- }*/
+ Vector3 position1;
+ Vector3 position2;
+ };
+ // 4 vertices 2 triangles per layer. The depth interval between each layer is 0.01
+ VertexPosition vertexData[12] = {
+ //bottom layer
+ { Vector3( -0.5f, -0.5f, 0.f ), Vector3( -0.5f, -0.5f, 0.f ) },
+ { Vector3( 0.5f, -0.5f, 0.f ), Vector3( 0.5f, -0.5f, 0.f ) },
+ { Vector3( -0.5f, -0.5f, 0.f ), Vector3( -0.5f, -0.5f + LAYER_HEIGHTS[0], 0.f ) },
+ { Vector3( 0.5f, -0.5f, 0.f ), Vector3( 0.5f, -0.5f+ LAYER_HEIGHTS[0], 0.f ) },
+ // middle layer
+ { Vector3( -0.5f, -0.5f, 0.01f ), Vector3( -0.5f, -0.5f, 0.01f ) },
+ { Vector3( 0.5f, -0.5f, 0.01f ), Vector3( 0.5f, -0.5f, 0.01f ) },
+ { Vector3( -0.5f, -0.5f, 0.01f ), Vector3( -0.5f, -0.5f + LAYER_HEIGHTS[1], 0.01f ) },
+ { Vector3( 0.5f, -0.5f, 0.01f ), Vector3( 0.5f, -0.5f+ LAYER_HEIGHTS[1], 0.01f ) },
+ // top layer
+ { Vector3( -0.5f, -0.5f, 0.02f ), Vector3( -0.5f, -0.5f, 0.02f ) },
+ { Vector3( 0.5f, -0.5f, 0.02f ), Vector3( 0.5f, -0.5f, 0.02f ) },
+ { Vector3( -0.5f, -0.5f, 0.02f ), Vector3( -0.5f, -0.5f + LAYER_HEIGHTS[2], 0.02f ) },
+ { Vector3( 0.5f, -0.5f, 0.02f ), Vector3( 0.5f, -0.5f+ LAYER_HEIGHTS[2], 0.02f ) }
+ };
+ Property::Map vertexFormat;
+ vertexFormat["aPosition1"] = Property::VECTOR3;
+ vertexFormat["aPosition2"] = Property::VECTOR3;
+ PropertyBuffer vertices = PropertyBuffer::New( PropertyBuffer::STATIC, vertexFormat, 12u );
+ vertices.SetData( vertexData );
+
+ unsigned int indexData[18] = { 0,3,1,0,2,3,4,7,5,4,6,7,8,11,9,8,10,11 };
+ Property::Map indexFormat;
+ indexFormat["indices"] = Property::UNSIGNED_INTEGER;
+ PropertyBuffer indices = PropertyBuffer::New( PropertyBuffer::STATIC, indexFormat, 18u );
+ indices.SetData( indexData );
+
+ Geometry meshGeometry = Geometry::New();
+ meshGeometry.AddVertexBuffer( vertices );
+ meshGeometry.SetIndexBuffer( indices );
+
+ // Create material
+ Shader shader = Shader::New( MESH_VERTEX_SHADER, MESH_FRAGMENT_SHADER );
+ Material material = Material::New( shader );
+
+ // Create renderer
+ Renderer renderer = Renderer::New( meshGeometry, material );
+
+ // Create actor
+ Actor meshActor= Actor::New();
+ meshActor.AddRenderer( renderer );
+
+ // Register property
+ bouncePropertyIndex = meshActor.RegisterProperty("bounce-coefficient", 0.f);
+ meshActor.AddUniformMapping( bouncePropertyIndex, "uBounceCoefficient" );
return meshActor;
}
mOvershoot(0.0f),
mAnimationStateFlags(0)
{
- /*
mOvershootOverlay = CreateBouncingEffectActor(mEffectOvershootProperty);
mOvershootOverlay.SetColor(mAttachedScrollView.GetOvershootEffectColor());
mOvershootOverlay.SetParentOrigin(ParentOrigin::TOP_LEFT);
mOvershootOverlay.SetAnchorPoint(AnchorPoint::TOP_LEFT);
mOvershootOverlay.SetDrawMode(DrawMode::OVERLAY);
mOvershootOverlay.SetVisible(false);
- */
+
}
void ScrollOvershootEffectRipple::Apply()
mOvershootProperty = IsVertical() ? Toolkit::ScrollView::Property::OVERSHOOT_Y : Toolkit::ScrollView::Property::OVERSHOOT_X;
// make sure height is set, since we only create a constraint for image width
- //mOvershootOverlay.SetSize(OVERSHOOT_BOUNCE_ACTOR_DEFAULT_SIZE.width, OVERSHOOT_BOUNCE_ACTOR_DEFAULT_SIZE.height);
+ mOvershootOverlay.SetSize(OVERSHOOT_BOUNCE_ACTOR_DEFAULT_SIZE.width, OVERSHOOT_BOUNCE_ACTOR_DEFAULT_SIZE.height);
- //mAttachedScrollView.AddOverlay(mOvershootOverlay);
+ mAttachedScrollView.AddOverlay(mOvershootOverlay);
UpdatePropertyNotifications();
}
void ScrollOvershootEffectRipple::Remove( Scrollable& scrollable )
{
-// if(mOvershootOverlay)
+ if(mOvershootOverlay)
{
if(mOvershootIncreaseNotification)
{
scrollable.Self().RemovePropertyNotification(mOvershootDecreaseNotification);
mOvershootDecreaseNotification.Reset();
}
- //scrollable.RemoveOverlay(mOvershootOverlay);
+ scrollable.RemoveOverlay(mOvershootOverlay);
}
}
void ScrollOvershootEffectRipple::Reset()
{
-// mOvershootOverlay.SetVisible(false);
-// mOvershootOverlay.SetProperty( mEffectOvershootProperty, 0.f);
+ mOvershootOverlay.SetVisible(false);
+ mOvershootOverlay.SetProperty( mEffectOvershootProperty, 0.f);
}
void ScrollOvershootEffectRipple::UpdatePropertyNotifications()
void ScrollOvershootEffectRipple::SetOvershootEffectColor( const Vector4& color )
{
+ if(mOvershootOverlay)
+ {
+ mOvershootOverlay.SetColor(color);
+ }
}
void ScrollOvershootEffectRipple::UpdateVisibility( bool visible )
{
+ mOvershootOverlay.SetVisible(visible);
+ // make sure overshoot image is correctly placed
+ if( visible )
+ {
+ Actor self = mAttachedScrollView.Self();
+ if(mOvershoot > 0.0f)
+ {
+ // positive overshoot
+ const Vector3 size = mOvershootOverlay.GetCurrentSize();
+ Vector3 relativeOffset;
+ const Vector3 parentSize = self.GetCurrentSize();
+ if(IsVertical())
+ {
+ mOvershootOverlay.SetOrientation( Quaternion( Radian( 0.0f ), Vector3::ZAXIS ) );
+ mOvershootOverlay.SetSize(parentSize.width, GetBounceActorHeight(parentSize.width), size.depth);
+ }
+ else
+ {
+ mOvershootOverlay.SetOrientation( Quaternion( Radian( 1.5f * Math::PI ), Vector3::ZAXIS ) );
+ mOvershootOverlay.SetSize(parentSize.height, GetBounceActorHeight(parentSize.height), size.depth);
+ relativeOffset = Vector3(0.0f, 1.0f, 0.0f);
+ }
+ mOvershootOverlay.SetPosition(relativeOffset * parentSize);
+ }
+ else
+ {
+ // negative overshoot
+ const Vector3 size = mOvershootOverlay.GetCurrentSize();
+ Vector3 relativeOffset;
+ const Vector3 parentSize = self.GetCurrentSize();
+ if(IsVertical())
+ {
+ mOvershootOverlay.SetOrientation( Quaternion( Radian( Math::PI ), Vector3::ZAXIS ) );
+ mOvershootOverlay.SetSize(parentSize.width, GetBounceActorHeight(parentSize.width), size.depth);
+ relativeOffset = Vector3(1.0f, 1.0f, 0.0f);
+ }
+ else
+ {
+ mOvershootOverlay.SetOrientation( Quaternion( Radian( 0.5f * Math::PI ), Vector3::ZAXIS ) );
+ mOvershootOverlay.SetSize(parentSize.height, GetBounceActorHeight(parentSize.height), size.depth);
+ relativeOffset = Vector3(1.0f, 0.0f, 0.0f);
+ }
+ mOvershootOverlay.SetPosition(relativeOffset * parentSize);
+ }
+ }
}
void ScrollOvershootEffectRipple::OnOvershootNotification(PropertyNotification& source)
if( animate && overshootAnimationSpeed > Math::MACHINE_EPSILON_0 )
{
- //float currentOvershoot = 0.0f;//fabsf( mOvershootOverlay.GetProperty( mEffectOvershootProperty ).Get<float>() );
- float duration = 0.05f;//mOvershootOverlay.GetCurrentSize().height * (animatingOn ? (1.0f - currentOvershoot) : currentOvershoot) / overshootAnimationSpeed;
+ float currentOvershoot = fabsf( mOvershootOverlay.GetProperty( mEffectOvershootProperty ).Get<float>() );
+ float duration = mOvershootOverlay.GetCurrentSize().height * (animatingOn ? (1.0f - currentOvershoot) : currentOvershoot) / overshootAnimationSpeed;
if( duration > Math::MACHINE_EPSILON_0 )
{
}
mScrollOvershootAnimation = Animation::New(duration);
mScrollOvershootAnimation.FinishedSignal().Connect( this, &ScrollOvershootEffectRipple::OnOvershootAnimFinished );
- //mScrollOvershootAnimation.AnimateTo( Property(mOvershootOverlay, mEffectOvershootProperty), amount, TimePeriod(duration) );
+ mScrollOvershootAnimation.AnimateTo( Property(mOvershootOverlay, mEffectOvershootProperty), amount, TimePeriod(duration) );
mScrollOvershootAnimation.Play();
mAnimationStateFlags = animatingOn ? AnimatingIn : AnimatingOut;
}
}
else
{
- //mOvershootOverlay.SetProperty( mEffectOvershootProperty, amount);
+ mOvershootOverlay.SetProperty( mEffectOvershootProperty, amount);
}
}
if( mAnimationStateFlags & AnimatingOut )
{
// should now be offscreen
- //mOvershootOverlay.SetVisible(false);
+ mOvershootOverlay.SetVisible(false);
}
if( (mAnimationStateFlags & AnimateBack) )
{