fdea5d0714b146004730f6cddf071acfb3eb4ae2
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / devel-api / shader-effects / dissolve-effect.h
1 #ifndef DALI_TOOLKIT_SHADER_EFFECT_DISSOLVE_H_
2 #define DALI_TOOLKIT_SHADER_EFFECT_DISSOLVE_H
3
4 /*
5  * Copyright (c) 2016 Samsung Electronics Co., Ltd.
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  * http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  */
20
21 // EXTERNAL INCLUDES
22 #include <string.h>
23 #include <dali/public-api/rendering/shader.h>
24
25 namespace Dali
26 {
27
28 namespace Toolkit
29 {
30
31 /**
32  * @brief Set the dissolve central line.
33  *
34  * Use one point (position) and one direction ( displacement ) vector to define this line
35  * As we use the texture coordinate as pixel position to calculate random offset,
36  * the line should passing through rectangle {(0,0),(0,1),(1,0),(1,1)},
37  * so make the position parameter with two component values between 0.0 to 1.0
38  * @param[in] actor The actor that registers the uniform properties
39  * @param[in] position The point ( locates within rectangle {(0,0),(0,1),(1,0),(1,1)} ) passed through by the central line
40  * @param[in] displacement The direction of the central line
41  * @param[in] initialProgress The normalised initial progress of the shader
42  */
43 inline void DissolveEffectSetCentralLine( Actor& actor, const Vector2& position, const Vector2& displacement, float initialProgress )
44 {
45   // the line passes through 'position' and has the direction of 'displacement'
46   float coefA, coefB, coefC; //line equation: Ax+By+C=0;
47   coefA = displacement.y;
48   coefB = -displacement.x;
49   coefC = -displacement.y*position.x + displacement.x*position.y;
50
51   float inversedAABB = 1.f / (coefA*coefA+coefB*coefB);
52   float inversedSqrtAABB = sqrtf(inversedAABB);
53   float saddleA;
54
55   //saddle surface(Hyperbolic paraboloid)function, used to calculate the dissolve starting time
56   //z = y*y/a/a - x*x/b/b
57   //with our selection of parameters(a and b), this value for any texture coordinate is between -1.0 and 1.0
58
59   Vector3 saddleParam; // [0]: a*a, [1]: b*b, [2] b
60   Vector2 translation;
61   Vector2 rotation;
62   float toNext = -1.f;
63   if( displacement.x > 0.f || (EqualsZero(displacement.x) && displacement.y > 0.f) )
64   {
65     toNext = 1.f;
66   }
67
68   if( (displacement.y * displacement.x < 0.0f) )
69   {
70     //distance from (0,0) to the line
71     float distanceTopLeft =  fabsf(coefC) * inversedSqrtAABB;
72     //distance from (1, 1 ) to the line
73     float distanceBottomRight = fabsf(coefA+coefB+coefC) * inversedSqrtAABB;
74     saddleA = std::max( distanceTopLeft, distanceBottomRight );
75
76     //foot of a perpendicular: (1,0) to the line
77     float footX1 = ( coefB*coefB - coefA*coefC) * inversedAABB;
78     float footY1 = (-coefA*coefB - coefB*coefC) * inversedAABB;
79     //foot of a perpendicular: (0,1) to the line
80     float footX2 = (-coefA*coefB - coefA*coefC) * inversedAABB;
81     float footY2 = ( coefA*coefA - coefB*coefC) * inversedAABB;
82     saddleParam[1] = (footX1-footX2)*(footX1-footX2) + (footY1-footY2)*(footY1-footY2);
83     translation = Vector2(-footX2,-footY2);
84   }
85   else
86   {
87     //distance from(1,0) to the line
88     float distanceTopRight = fabsf(coefA+coefC) * inversedSqrtAABB;
89     //distance from(0,1) to the line
90     float distanceBottomLeft = fabsf(coefB+coefC) * inversedSqrtAABB;
91     saddleA = std::max( distanceTopRight, distanceBottomLeft );
92     //foot of a perpendicular: (0,0) to the line
93     float footX3 = (-coefA*coefC) * inversedAABB;
94     float footY3 = (-coefB*coefC) * inversedAABB;
95     //foot of a perpendicular: (1.0,1.0) to the line
96     float footX4 = ( coefB*coefB - coefA*coefB - coefA*coefC) * inversedAABB;
97     float footY4 = (-coefA*coefB + coefA*coefA- coefB*coefC) * inversedAABB;
98     saddleParam[1] = (footX3-footX4)*(footX3-footX4) + (footY3-footY4)*(footY3-footY4);
99     translation = Vector2(-footX3, -footY3);
100   }
101
102   saddleParam[2] = sqrtf(saddleParam[1]);
103   saddleParam[0] = saddleA*saddleA;
104   rotation = Vector2(-displacement.x, displacement.y);
105   rotation.Normalize();
106
107   actor.RegisterProperty( "uSaddleParam", saddleParam );
108   actor.RegisterProperty( "uTranslation", translation );
109   actor.RegisterProperty( "uRotation", rotation );
110   actor.RegisterProperty( "uToNext", toNext );
111   actor.RegisterProperty( "uPercentage", initialProgress, Dali::Property::ANIMATABLE );
112 }
113 /**
114  * @brief Create a new Dissolve effect
115  *
116  *  DissolveEffect is a custom shader effect to achieve Dissolve effects in image views.
117  *
118  *  Animatable/Constrainable uniforms:
119  *    "uPercentage" - This value is proportional to the distortion applied; a value of zero means no distortion.
120  *
121  *  @param[in] useHighPrecision True if using high precision in fragment shader for fully random noise, false otherwise
122  *  @return The newly created Property::Map with the dissolve effect
123  */
124
125 inline Property::Map CreateDissolveEffect( bool useHighPrecision = true )
126 {
127   const char* prefixHighPrecision( "precision highp float;\n");
128   const char* prefixMediumPrecision( "precision mediump float;\n" );
129
130   const char* vertexShader( DALI_COMPOSE_SHADER(
131     attribute mediump vec2 aPosition;\n
132     \n
133     uniform mediump mat4 uMvpMatrix;\n
134     uniform vec3 uSize;\n
135     uniform vec4 uTextureRect;
136     \n
137     uniform float uPercentage;\n
138     uniform vec3 uSaddleParam;\n
139     uniform vec2 uTranslation;\n
140     uniform vec2 uRotation; \n
141     uniform float uToNext;\n
142     \n
143     varying float vPercentage;\n
144     varying vec2 vTexCoord;\n
145
146     void main()\n
147     {\n
148       mediump vec4 vertexPosition = vec4(aPosition, 0.0, 1.0);\n
149       vertexPosition.xyz *= uSize;\n
150       vertexPosition = uMvpMatrix * vertexPosition;\n
151       gl_Position = vertexPosition;\n
152
153       vec2 texCoord = aPosition + vec2(0.5);
154       vTexCoord = texCoord;\n
155       //Calculate the distortion value given the dissolve central line
156       vec2 value = texCoord + uTranslation; \n
157       mat2 rotateMatrix = mat2( uRotation.s, uRotation.t, -uRotation.t, uRotation.s ); \n
158       value = rotateMatrix * value; \n
159       if(uToNext == 1.0)  \n
160         value.s = uSaddleParam[2] + value.s; \n
161       float delay = value.t*value.t / uSaddleParam[0] - value.s*value.s/uSaddleParam[1];\n
162       vPercentage = clamp( uPercentage*2.0 - 0.5*sin(delay*1.571) - 0.5, 0.0, 1.0 ); \n
163     })
164   );
165
166   const char* fragmentShader( DALI_COMPOSE_SHADER(
167     varying float vPercentage;\n
168     varying mediump vec2 vTexCoord;\n
169     \n
170     uniform sampler2D sTexture;\n
171     uniform lowp vec4 uColor;\n
172     uniform vec4 uTextureRect;
173     \n
174     float rand(vec2 co) \n
175     {\n
176       return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453); \n
177     }\n
178     \n
179     void main()\n
180     {\n
181
182       //Calculate the randomness
183       float offsetS = rand( vTexCoord * vPercentage ) - vTexCoord.s; \n
184       float offsetT = rand( vec2(vTexCoord.t*vPercentage, vTexCoord.s * vPercentage) ) - vTexCoord.t; \n
185       vec2 lookupCoord = vTexCoord + vec2(offsetS, offsetT) * vPercentage; \n
186       gl_FragColor = texture2D( sTexture, lookupCoord ) * uColor; \n
187       gl_FragColor.a *= 1.0 - vPercentage; \n
188     } )
189   );
190
191   Property::Map map;
192
193   Property::Map customShader;
194
195   std::string vertexShaderString;
196   std::string fragmentShaderString;
197   if( useHighPrecision )
198   {
199     vertexShaderString.reserve(strlen( prefixHighPrecision ) + strlen( vertexShader ));
200     vertexShaderString.append( prefixHighPrecision );
201
202     fragmentShaderString.reserve(strlen( prefixHighPrecision ) + strlen( fragmentShader ));
203     fragmentShaderString.append( prefixHighPrecision );
204   }
205   else
206   {
207     vertexShaderString.reserve(strlen( prefixMediumPrecision ) + strlen( vertexShader ));
208     vertexShaderString.append( prefixMediumPrecision );
209
210     fragmentShaderString.reserve(strlen( prefixMediumPrecision ) + strlen( fragmentShader ));
211     fragmentShaderString.append( prefixMediumPrecision );
212   }
213
214   vertexShaderString.append( vertexShader );
215   fragmentShaderString.append( fragmentShader );
216
217   customShader[ "vertexShader" ] = vertexShaderString;
218   customShader[ "fragmentShader" ] = fragmentShaderString;
219
220   customShader[ "subdivideGridX" ] = 20;
221   customShader[ "subdivideGridY" ] = 20;
222
223   customShader[ "hints" ] = "outputIsTransparent";
224
225   map[ "shader" ] = customShader;
226   return map;
227 }
228
229 } // namespace Toolkit
230
231 } // namespace Dali
232
233 #endif // DALI_TOOLKIT_SHADER_EFFECT_DISSOLVE_H