/*
- * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2016 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.
*
*/
+// EXTERNAL INCLUDES
+#include <string.h>
+#include <dali/public-api/animation/constraint.h>
+#include <dali/public-api/actors/actor.h>
+#include <dali/public-api/object/property-map.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/visuals/visual-properties.h>
#include <dali-toolkit/internal/controls/page-turn-view/page-turn-effect.h>
-#include <dali/public-api/math/matrix.h>
using namespace Dali;
using namespace Dali::Toolkit;
-void CommonParametersConstraint( Dali::Matrix& current, const PropertyInputContainer& inputs )
+namespace
{
- const Vector2& originalCenter = inputs[0]->GetVector2();
- Vector2 currentCenter = inputs[1]->GetVector2();
- const Vector2& pageSize = inputs[2]->GetVector2();
+#define DALI_COMPOSE_SHADER(STR) #STR
+const char * const PROPERTY_COMMON_PARAMETERS( "uCommonParameters" );
+const char * const PROPERTY_ORIGINAL_CENTER( "originalCenter" );
+const char * const PROPERTY_CURRENT_CENTER( "currentCenter" );
+}
- // calculate the curve direction and the vanishing point
- // here, the vanishing point is the intersection of spine with the line passing through original center and vertical to curve direction
- Vector2 curveDirection( currentCenter - originalCenter );
- curveDirection.Normalize();
- if( fabs(curveDirection.y) < 0.01f) // eliminate the possibility of division by zero in the next step
- {
- curveDirection.y = 0.01f;
- }
- float vanishingPointY = originalCenter.y + curveDirection.x * originalCenter.x / curveDirection.y;
+/**
+ * This constraint updates the common parameter values used by every vertex.
+ * By using constraint, they are calculate once in CPU then pass into the vertex shader as uniforms
+ */
+struct CommonParametersConstraint
+{
+ CommonParametersConstraint( float pageHeight )
+ : mPageHeight( pageHeight )
+ {}
- float curveEndY, cosTheta ,sinTheta ,translateX, translateY;
- // when the vanishing point is very far away, make it infinitely, in this case, the page bent horizontally
- const float THRESHOLD(20.0);
- if( fabs(vanishingPointY-pageSize.y*0.5f) >= pageSize.y*THRESHOLD )
+ void operator()( Dali::Matrix& current, const PropertyInputContainer& inputs )
{
- curveDirection = Vector2(-1.f,0.f);
- currentCenter.y = originalCenter.y;
+ const Vector2& originalCenter = inputs[0]->GetVector2();
+ Vector2 currentCenter = inputs[1]->GetVector2();
- curveEndY = originalCenter.y;
- cosTheta = 1.f;
- sinTheta = 0.f;
- translateX = currentCenter.x - originalCenter.x;
- translateY = vanishingPointY;
- }
- else
- {
- curveEndY = currentCenter.y - curveDirection.y * (currentCenter.x/curveDirection.x) ;
- Vector2 v1( currentCenter.x, currentCenter.y - vanishingPointY );
- v1.Normalize();
- Vector2 v2( originalCenter.x, originalCenter.y - vanishingPointY );
- v2.Normalize();
- cosTheta = v1.x*v2.x + v1.y*v2.y;
- sinTheta = ( vanishingPointY > pageSize.y*0.5f ) ? sqrt(1.0-cosTheta*cosTheta) : -sqrt(1.0-cosTheta*cosTheta);
- translateX = currentCenter.x - cosTheta*originalCenter.x - sinTheta*( originalCenter.y-vanishingPointY );
- translateY = currentCenter.y + sinTheta*originalCenter.x - cosTheta*( originalCenter.y-vanishingPointY );
- }
+ // calculate the curve direction and the vanishing point
+ // here, the vanishing point is the intersection of spine with the line passing through original center and vertical to curve direction
+ Vector2 curveDirection( currentCenter - originalCenter );
+ curveDirection.Normalize();
+ if( fabs(curveDirection.y) < 0.01f) // eliminate the possibility of division by zero in the next step
+ {
+ curveDirection.y = 0.01f;
+ }
+ float vanishingPointY = originalCenter.y + curveDirection.x * originalCenter.x / curveDirection.y;
- float originalLength = fabs(originalCenter.x/curveDirection.x);
- float currentLength = fabs(currentCenter.x/curveDirection.x);
- float curveHeight = 0.45f*sqrt(originalLength*originalLength - currentLength*currentLength);
+ float curveEndY, cosTheta ,sinTheta ,translateX, translateY;
+ // when the vanishing point is very far away, make it infinitely, in this case, the page bent horizontally
+ const float THRESHOLD(20.0);
+ if( fabs(vanishingPointY-mPageHeight*0.5f) >= mPageHeight*THRESHOLD )
+ {
+ curveDirection = Vector2(-1.f,0.f);
+ currentCenter.y = originalCenter.y;
- float* parameterArray = current.AsFloat();
- parameterArray[0] = cosTheta;
- parameterArray[1] = -sinTheta;
- parameterArray[2] = originalCenter.x;
- parameterArray[3] = originalCenter.y;
- parameterArray[4] = sinTheta;
- parameterArray[5] = cosTheta;
- parameterArray[6] = currentCenter.x;
- parameterArray[7] = currentCenter.y;
- parameterArray[8] = translateX;
- parameterArray[9] = translateY;
- parameterArray[10] = vanishingPointY;
- parameterArray[11] = curveEndY;
- parameterArray[12] = curveDirection.x;
- parameterArray[13] = curveDirection.y;
- parameterArray[14] = curveHeight;
- parameterArray[15] = currentLength;
-}
+ curveEndY = originalCenter.y;
+ cosTheta = 1.f;
+ sinTheta = 0.f;
+ translateX = currentCenter.x - originalCenter.x;
+ translateY = vanishingPointY;
+ }
+ else
+ {
+ curveEndY = currentCenter.y - curveDirection.y * (currentCenter.x/curveDirection.x) ;
+ Vector2 v1( currentCenter.x, currentCenter.y - vanishingPointY );
+ v1.Normalize();
+ Vector2 v2( originalCenter.x, originalCenter.y - vanishingPointY );
+ v2.Normalize();
+ cosTheta = v1.x*v2.x + v1.y*v2.y;
+ sinTheta = ( vanishingPointY > mPageHeight*0.5f ) ? sqrt(1.0-cosTheta*cosTheta) : -sqrt(1.0-cosTheta*cosTheta);
+ translateX = currentCenter.x - cosTheta*originalCenter.x - sinTheta*( originalCenter.y-vanishingPointY );
+ translateY = currentCenter.y + sinTheta*originalCenter.x - cosTheta*( originalCenter.y-vanishingPointY );
+ }
+
+ float originalLength = fabs(originalCenter.x/curveDirection.x);
+ float currentLength = fabs(currentCenter.x/curveDirection.x);
+ float curveHeight = 0.45f*sqrt(originalLength*originalLength - currentLength*currentLength);
+
+ float* parameterArray = current.AsFloat();
+ parameterArray[0] = cosTheta;
+ parameterArray[1] = -sinTheta;
+ parameterArray[2] = originalCenter.x;
+ parameterArray[3] = originalCenter.y;
+ parameterArray[4] = sinTheta;
+ parameterArray[5] = cosTheta;
+ parameterArray[6] = currentCenter.x;
+ parameterArray[7] = currentCenter.y;
+ parameterArray[8] = translateX;
+ parameterArray[9] = translateY;
+ parameterArray[10] = vanishingPointY;
+ parameterArray[11] = curveEndY;
+ parameterArray[12] = curveDirection.x;
+ parameterArray[13] = curveDirection.y;
+ parameterArray[14] = curveHeight;
+ parameterArray[15] = currentLength;
+ }
+
+ float mPageHeight;
+};
-void Dali::Toolkit::Internal::PageTurnApplyInternalConstraint( ShaderEffect& shaderEffect)
+void Dali::Toolkit::Internal::PageTurnApplyInternalConstraint( Actor& actor, float pageHeight )
{
- Constraint constraint = Constraint::New<Dali::Matrix>( shaderEffect, shaderEffect.GetPropertyIndex( "uCommonParameters" ), CommonParametersConstraint );
- constraint.AddSource( LocalSource( shaderEffect.GetPropertyIndex( "uOriginalCenter" ) ) );
- constraint.AddSource( LocalSource( shaderEffect.GetPropertyIndex( "uCurrentCenter" ) ) );
- constraint.AddSource( LocalSource( shaderEffect.GetPropertyIndex( "uPageSize" ) ) );
+ Constraint constraint = Constraint::New<Dali::Matrix>( actor, actor.GetPropertyIndex( PROPERTY_COMMON_PARAMETERS ) , CommonParametersConstraint( pageHeight ) );
+ constraint.AddSource( LocalSource( actor.GetPropertyIndex( PROPERTY_ORIGINAL_CENTER ) ) );
+ constraint.AddSource( LocalSource( actor.GetPropertyIndex( PROPERTY_CURRENT_CENTER ) ) );
constraint.Apply();
}
-ShaderEffect Dali::Toolkit::Internal::CreatePageTurnEffect()
+Property::Map Dali::Toolkit::Internal::CreatePageTurnEffect()
{
- std::string vertexShader = DALI_COMPOSE_SHADER(
+ const char* vertexShader = DALI_COMPOSE_SHADER(
/*
* The common parameters for all the vertices, calculate in CPU then pass into the shader as uniforms
*
* ([3][3]) float currentLength: The length from the current center to the curveEnd.
*/
precision mediump float;\n
+ \n
+ attribute mediump vec2 aPosition;\n
+ \n
+ uniform mediump mat4 uMvpMatrix;\n
+ uniform mediump mat3 uNormalMatrix;\n
+ uniform mediump mat4 uModelView;\n
+ \n
uniform mat4 uCommonParameters;\n
\n
- uniform vec2 uPageSize;\n
+ uniform vec3 uSize;\n
uniform float uIsTurningBack;\n
+ uniform float uTextureWidth;\n
varying vec3 vNormal;\n
varying vec4 vPosition;\n
- varying float vEdgeShadow;\n
+ varying mediump vec2 vTexCoord;\n
\n
void main()\n
{\n
- vec4 position = vec4( aPosition.xy, 0.0, 1.0);\n
+ vec4 position = vec4( aPosition*uSize.xy, 0.0, 1.0);\n
vec2 currentCenter = vec2( uCommonParameters[1][2], uCommonParameters[1][3]);\n
vec2 originalCenter = vec2( uCommonParameters[0][2], uCommonParameters[0][3]);\n
vec3 normal = vec3(0.0,0.0,1.0);\n
if(currentCenter.x < originalCenter.x)\n
{\n
// change the coordinate origin from the center of the page to its top-left
- position.xy += uPageSize * 0.5;\n
+ position.xy += uSize.xy * 0.5;\n
vec2 curveDirection = vec2( uCommonParameters[3]);\n
vec3 vanishingPoint = vec3(0.0, uCommonParameters[2][2], 0.0);\n
// first part of the page, (outside the the line passing through original center and vertical to curve direction)
}\n
\n
// define the control points of hermite curve, composed with two segments
- // calulation is carried out on the 2D plane which is passing through both current and original center and vertical to the image plane
+ // calculation is carried out on the 2D plane which is passing through both current and original center and vertical to the image plane
float currentLength = uCommonParameters[3][3];\n
float originalLength = abs(originalCenter.x/curveDirection.x);\n
float height = uCommonParameters[3][2];\n
vec2 SegmentTwoTangentVector0 = SegmentOneTangentVector1;\n
vec2 SegmentTwoTangentVector1 = SegmentOneTangentVector1;\n
\n
- // calulate the corresponding curve point position and its tangent vector
+ // calculate the corresponding curve point position and its tangent vector
// it is a linear mapping onto nonlinear curves, might cause some unwanted deformation
// but as there are no analytical method to calculate the curve length on arbitrary segment
// no efficient way to solve this nonlinear mapping, Numerical approximation would cost too much computation in shader
// a trick to eliminate some optical illusion caused by the gradient matter of normal in per-fragment shading
// which is caused by linear interpolation of normal vs. nonlinear lighting
// will notice some artifact in the areas with dramatically normal changes, so compress the normal differences here
- tangent.y *= min(1.0, length(position.xyz - vanishingPoint) / uPageSize.y ); \n
+ tangent.y *= min(1.0, length(position.xyz - vanishingPoint) / uSize.y ); \n
}\n
vec3 curvePoint = vec3(curveEnd - curvePoint2D.x*curveDirection,max(0.0,curvePoint2D.y));\n
vec3 tangentVector = vec3(-tangent.x*curveDirection,tangent.y);\n
normal.xy *= -uIsTurningBack;\n
}\n
// change the coordinate origin from the top-left of the page to its center
- position.xy -= uPageSize * 0.5; \n
+ position.xy -= uSize.xy * 0.5; \n
}\n
- position.z += aPosition.z;\n
- gl_Position = uMvpMatrix * position;\n
+ vNormal = uNormalMatrix * normal;\n
+ gl_Position = uMvpMatrix * position;
// varying parameters for fragment shader
- vTexCoord = aTexCoord;
- vNormal = uNormalMatrix*normal;\n
+ vTexCoord = aPosition + vec2(0.5);\n
+ vTexCoord.x /= uTextureWidth;
vPosition = uModelView * position;\n
}\n
);
- std::string fragmentShader = DALI_COMPOSE_SHADER(
+ const char* fragmentShader = DALI_COMPOSE_SHADER(
precision mediump float;\n
- uniform vec2 uPageSize;\n
+ \n
+ varying mediump vec2 vTexCoord;\n
+ \n
+ uniform sampler2D sTexture;\n
+ uniform lowp vec4 uColor;\n
+ uniform vec3 uSize;\n
uniform vec2 uSpineShadowParameter;\n
varying vec3 vNormal;\n
varying vec4 vPosition;\n
- varying float vEdgeShadow;\n
\n
void main()\n
{\n
// need to re-normalize the interpolated normal
- vec3 normal = normalize(vNormal);\n
- vec4 texel;\n
- float spineShadowCoef = 1.0; \n
+ vec3 normal = normalize( vNormal );\n
// display page content
+ vec4 texel;
// display back image of the page, flip the texture
- if( dot(vPosition.xyz, normal) > 0.0 ) texel = texture2D( sTexture, vec2( sTextureRect.p+sTextureRect.s-vTexCoord.x, vTexCoord.y ) );\n
+ if( dot(vPosition.xyz, normal) > 0.0 ) texel = texture2D( sTexture, vec2( 1.0 - vTexCoord.x, vTexCoord.y ) );\n
// display front image of the page
else texel = texture2D( sTexture, vTexCoord );\n
+
// display book spine, a stripe of shadowed texture
- float pixelPos = (vTexCoord.x-sTextureRect.s)*uPageSize.x; \n
- if(pixelPos < uSpineShadowParameter.x) \n
+ float pixelPos = vTexCoord.x * uSize.x; \n
+ float spineShadowCoef = 1.0; \n
+ if( pixelPos < uSpineShadowParameter.x ) \n
{\n
float x = pixelPos - uSpineShadowParameter.x;\n
- float y = sqrt( uSpineShadowParameter.x*uSpineShadowParameter.x - x*x);\n
+ float y = sqrt( uSpineShadowParameter.x*uSpineShadowParameter.x - x*x );\n
spineShadowCoef = normalize( vec2( uSpineShadowParameter.y*x/uSpineShadowParameter.x, y ) ).y;\n
}\n
// calculate the lighting
// set the ambient color as vec3(0.4);
float lightColor = abs( normal.z ) * 0.6 + 0.4;\n
- gl_FragColor = vec4( ( spineShadowCoef* lightColor)* texel.rgb , texel.a ) * uColor;\n
+ gl_FragColor = vec4( ( spineShadowCoef * lightColor ) * texel.rgb , texel.a ) * uColor;\n
}
);
- // Create the implementation, temporarily owned on stack,
- Dali::ShaderEffect shaderEffectCustom = Dali::ShaderEffect::New( vertexShader, fragmentShader,ShaderEffect::HINT_GRID );
-
- static const Vector2 DEFAULT_SPINE_SHADOW_PARAMETER(50.0f, 20.0f);
-
- Vector2 defaultPageSize = Dali::Stage::GetCurrent().GetSize();
- Dali::Matrix zeroMatrix(true);
- shaderEffectCustom.SetUniform( "uCommonParameters", zeroMatrix );
- shaderEffectCustom.SetUniform( "uPageSize", defaultPageSize );
- shaderEffectCustom.SetUniform( "uSpineShadowParameter", DEFAULT_SPINE_SHADOW_PARAMETER );
+ Property::Map map;
- shaderEffectCustom.RegisterProperty( "uOriginalCenter", Vector2( defaultPageSize[0], defaultPageSize[1]*0.5f ) );
- shaderEffectCustom.RegisterProperty( "uCurrentCenter", Vector2( defaultPageSize[0], defaultPageSize[1]*0.5f ) );
+ Property::Map customShader;
- PageTurnApplyInternalConstraint(shaderEffectCustom);
+ customShader[ Toolkit::Visual::Shader::Property::VERTEX_SHADER ] = vertexShader;
+ customShader[ Toolkit::Visual::Shader::Property::FRAGMENT_SHADER ] = fragmentShader;
+ customShader[ Toolkit::Visual::Shader::Property::SUBDIVIDE_GRID_X ] = 20;
+ customShader[ Toolkit::Visual::Shader::Property::SUBDIVIDE_GRID_Y ] = 20;
- // setting isTurningBack to -1.0f here means turning page forward
- shaderEffectCustom.SetUniform( "uIsTurningBack", -1.0f );
+ map[ Toolkit::Visual::Property::SHADER ] = customShader;
+ return map;
- return shaderEffectCustom;
}