X-Git-Url: http://review.tizen.org/git/?p=platform%2Fcore%2Fuifw%2Fdali-toolkit.git;a=blobdiff_plain;f=dali-toolkit%2Finternal%2Fcontrols%2Fpage-turn-view%2Fpage-turn-effect.cpp;h=15a48daa20e5a8fcbd120bbfea2090a8480eddae;hp=01692108dcfe097bd3e49eea9d82aeca02f10960;hb=b1e8521ad77e7b4e62b59613b2edef64429130e9;hpb=4eb683ee97fc0d8a7278b50252a467b843f869df diff --git a/dali-toolkit/internal/controls/page-turn-view/page-turn-effect.cpp b/dali-toolkit/internal/controls/page-turn-view/page-turn-effect.cpp index 0169210..15a48da 100644 --- a/dali-toolkit/internal/controls/page-turn-view/page-turn-effect.cpp +++ b/dali-toolkit/internal/controls/page-turn-view/page-turn-effect.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015 Samsung Electronics Co., Ltd. + * Copyright (c) 2017 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. @@ -15,90 +15,116 @@ * */ +// EXTERNAL INCLUDES +#include +#include +#include +#include + +// INTERNAL INCLUDES +#include #include -#include 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 ); + } -void Dali::Toolkit::Internal::PageTurnApplyInternalConstraint( ShaderEffect& shaderEffect) + 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( Actor& actor, float pageHeight ) { - Constraint constraint = Constraint::New( 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( 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(bool enableBlending) +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 * @@ -117,18 +143,25 @@ ShaderEffect Dali::Toolkit::Internal::CreatePageTurnEffect(bool enableBlending) * ([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 uShadowWidth;\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 @@ -136,7 +169,7 @@ ShaderEffect Dali::Toolkit::Internal::CreatePageTurnEffect(bool enableBlending) 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) @@ -165,7 +198,7 @@ ShaderEffect Dali::Toolkit::Internal::CreatePageTurnEffect(bool enableBlending) }\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 @@ -179,7 +212,7 @@ ShaderEffect Dali::Toolkit::Internal::CreatePageTurnEffect(bool enableBlending) 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 @@ -208,7 +241,7 @@ ShaderEffect Dali::Toolkit::Internal::CreatePageTurnEffect(bool enableBlending) // 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 @@ -245,122 +278,66 @@ ShaderEffect Dali::Toolkit::Internal::CreatePageTurnEffect(bool enableBlending) 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 - ); - - std::string vertexShaderWithFakedShadow = DALI_COMPOSE_SHADER( - // display shadow, the fake shadow value is calculated according to the height and the distance from page edge - vTexCoord.x = (aTexCoord.x-sTextureRect.s) /( 1.0 - uShadowWidth ) + sTextureRect.s;\n - vTexCoord.y = ( aTexCoord.y-sTextureRect.t-0.5*uShadowWidth*(sTextureRect.q-sTextureRect.t) )/( 1.0 - uShadowWidth ) + sTextureRect.t;\n - float heightCoef = (1.0 + position.z*uIsTurningBack*3.0 / uPageSize.x) * 0.6; - vEdgeShadow = clamp(0.9 - heightCoef, 0.0, 0.9 ); \n - if( vTexCoord.y >= sTextureRect.q || vTexCoord.y <= sTextureRect.t || vTexCoord.x >= sTextureRect.p )\n - {\n - float inversedShadowWidth = (1.0-uShadowWidth) / uShadowWidth ;\n - float alpha1 = (vTexCoord.x-sTextureRect.p) * inversedShadowWidth / (sTextureRect.p - sTextureRect.s);\n - inversedShadowWidth = 2.0 * inversedShadowWidth / (sTextureRect.q - sTextureRect.t); \n - float alpha2 = (vTexCoord.y-sTextureRect.q) * inversedShadowWidth;\n - float alpha3 = (sTextureRect.t-vTexCoord.y) * inversedShadowWidth;\n - float alpha;\n - if(alpha1 > 0.0 && alpha2 > 0.0) alpha = sqrt(alpha2*alpha2+alpha1*alpha1)/sqrt(1.0 + max(alpha1,alpha2)*max(alpha1,alpha2));\n //bottom-right corner - else if(alpha1 > 0.0 && alpha3 > 0.0) alpha = sqrt(alpha3*alpha3+alpha1*alpha1)/sqrt(1.0+max(alpha1,alpha3)*max(alpha1,alpha3));\n //top-right corner - else alpha = max(alpha1,max(alpha2,alpha3)); \n - alpha = 0.9 - alpha*0.9;\n - vEdgeShadow = clamp(alpha - heightCoef, 0.0, 0.9 ); \n }\n ); - std::string vertexShaderEnd("}"); - - std::string fragmentShaderPartOne = 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 - ); - - std::string fragmentShaderWithFakedShadow = DALI_COMPOSE_SHADER( - if( vTexCoord.y > sTextureRect.q || vTexCoord.y < sTextureRect.t || vTexCoord.x > sTextureRect.p )\n - texel = vec4(0.0,0.0,0.0,vEdgeShadow); - else \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( 1.0 - vTexCoord.x, vTexCoord.y ) );\n + // display front image of the page + else texel = texture2D( sTexture, vTexCoord );\n - std::string fragmentShaderPartTwo = DALI_COMPOSE_SHADER( - { \n - // display page content - // 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 - // 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 - {\n - float x = pixelPos - uSpineShadowParameter.x;\n - float y = sqrt( uSpineShadowParameter.x*uSpineShadowParameter.x - x*x);\n - spineShadowCoef = normalize( vec2( uSpineShadowParameter.y*x/uSpineShadowParameter.x, y ) ).y;\n - }\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 + // display book spine, a stripe of shadowed texture + 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 + 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 } ); - // Create the implementation, temporarily owned on stack, - Dali::ShaderEffect shaderEffectCustom; - std::ostringstream vertexShaderStringStream; - std::ostringstream fragmentShaderStringStream; - if( enableBlending ) - { - vertexShaderStringStream<< vertexShader << vertexShaderWithFakedShadow << vertexShaderEnd; - fragmentShaderStringStream<< fragmentShaderPartOne << fragmentShaderWithFakedShadow << fragmentShaderPartTwo; - shaderEffectCustom = Dali::ShaderEffect::New( vertexShaderStringStream.str(), fragmentShaderStringStream.str(), GeometryType( GEOMETRY_TYPE_IMAGE ), - ShaderEffect::GeometryHints( ShaderEffect::HINT_GRID | ShaderEffect::HINT_DEPTH_BUFFER | ShaderEffect::HINT_BLENDING) ); - } - else - { - vertexShaderStringStream<< vertexShader << vertexShaderEnd; - fragmentShaderStringStream<< fragmentShaderPartOne << fragmentShaderPartTwo; - shaderEffectCustom = Dali::ShaderEffect::New( vertexShaderStringStream.str(), fragmentShaderStringStream.str(), GeometryType( GEOMETRY_TYPE_IMAGE ), - ShaderEffect::GeometryHints( ShaderEffect::HINT_GRID | ShaderEffect::HINT_DEPTH_BUFFER ) ); - } - - static const float DEFAULT_SHADOW_WIDTH(0.15f); - static const Vector2 DEFAULT_SPINE_SHADOW_PARAMETER(50.0f, 20.0f); + Property::Map map; - Vector2 defaultPageSize = Dali::Stage::GetCurrent().GetSize(); - Dali::Matrix zeroMatrix(true); - shaderEffectCustom.SetUniform( "uCommonParameters", zeroMatrix ); - shaderEffectCustom.SetUniform( "uPageSize", defaultPageSize/(1.f-DEFAULT_SHADOW_WIDTH) ); - shaderEffectCustom.SetUniform( "uShadowWidth", DEFAULT_SHADOW_WIDTH ); - shaderEffectCustom.SetUniform( "uSpineShadowParameter", DEFAULT_SPINE_SHADOW_PARAMETER ); + Property::Map customShader; - shaderEffectCustom.RegisterProperty( "uOriginalCenter", Vector2( defaultPageSize[0], defaultPageSize[1]*0.5f ) ); - shaderEffectCustom.RegisterProperty( "uCurrentCenter", Vector2( defaultPageSize[0], defaultPageSize[1]*0.5f ) ); + 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; - PageTurnApplyInternalConstraint(shaderEffectCustom); + map[ Toolkit::Visual::Property::SHADER ] = customShader; + return map; - // setting isTurningBack to -1.0f here means turning page forward - shaderEffectCustom.SetUniform( "uIsTurningBack", -1.0f ); - - return shaderEffectCustom; } -