4953e4db027618c87cf9af66496753e8f7491a7f
[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) 2015 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/devel-api/rendering/shader.h>
24
25 namespace Dali
26 {
27
28 namespace Toolkit
29 {
30
31 /**
32  * @brief Only registers the required property if it has not registered it before.
33  *
34  * @tparam  T  The type of the property.
35  *
36  * @param[in]  actor  The actor to register the property with.
37  * @param[in]  name   The name of the property.
38  * @param[in]  value  The value the property should be set to.
39  */
40 template < typename T>
41 DALI_INTERNAL void SafeSetCustomProperty( Dali::Actor& actor, const std::string& name, const T& value )
42 {
43   Dali::Property::Index index = actor.GetPropertyIndex( name );
44   if ( Dali::Property::INVALID_INDEX == index )
45   {
46     index = actor.RegisterProperty( name, value );
47   }
48   else
49   {
50     actor.SetProperty( index, value );
51   }
52 }
53
54 /**
55  * @brief Only registers the required property if it has not registered it before.
56  *
57  * @tparam  T  The type of the property.
58  *
59  * @param[in]  actor       The actor to register the property with.
60  * @param[in]  name        The name of the property.
61  * @param[in]  value       The value the property should be set to.
62  * @param[in]  accessMode  The accessMode required for the property.
63  */
64 template < typename T>
65 DALI_INTERNAL void SafeSetCustomProperty( Dali::Actor& actor, const std::string& name, const T& value, Dali::Property::AccessMode accessMode )
66 {
67   Dali::Property::Index index = actor.GetPropertyIndex( name );
68   if ( Dali::Property::INVALID_INDEX == index )
69   {
70     index = actor.RegisterProperty( name, value, accessMode );
71   }
72   else
73   {
74     actor.SetProperty( index, value );
75   }
76 }
77
78 /**
79  * @brief Set the dissolve central line.
80  *
81  * Use one point (position) and one direction ( displacement ) vector to define this line
82  * As we use the texture coordinate as pixel position to calculate random offset,
83  * the line should passing through rectangle {(0,0),(0,1),(1,0),(1,1)},
84  * so make the position parameter with two component values between 0.0 to 1.0
85  * @param[in] position The point ( locates within rectangle {(0,0),(0,1),(1,0),(1,1)} ) passed through by the central line
86  * @param[in] displacement The direction of the central line
87  * @param[in] initialProgress, the normalised initial progress of the shader
88  */
89 inline void DissolveEffectSetCentralLine( Actor& actor, const Vector2& position, const Vector2& displacement, float initialProgress )
90 {
91   // the line passes through 'position' and has the direction of 'displacement'
92     float coefA, coefB, coefC; //line equation: Ax+By+C=0;
93     coefA = displacement.y;
94     coefB = -displacement.x;
95     coefC = -displacement.y*position.x + displacement.x*position.y;
96
97     float inversedAABB = 1.f / (coefA*coefA+coefB*coefB);
98     float inversedSqrtAABB = sqrtf(inversedAABB);
99     float saddleA;
100
101     //saddle surface(Hyperbolic paraboloid)function, used to calculate the dissolve starting time
102     //z = y*y/a/a - x*x/b/b
103     //with our selection of parameters(a and b), this value for any texture coordinate is between -1.0 and 1.0
104
105     Vector3 saddleParam; // [0]: a*a, [1]: b*b, [2] b
106     Vector2 translation;
107     Vector2 rotation;
108     float toNext = -1.f;
109     if( displacement.x > 0.f || (EqualsZero(displacement.x) && displacement.y > 0.f) )
110     {
111       toNext = 1.f;
112     }
113
114     if( (displacement.y * displacement.x < 0.0f) )
115     {
116       //distance from (0,0) to the line
117       float distanceTopLeft =  fabsf(coefC) * inversedSqrtAABB;
118       //distance from (1, 1 ) to the line
119       float distanceBottomRight = fabsf(coefA+coefB+coefC) * inversedSqrtAABB;
120       saddleA = std::max( distanceTopLeft, distanceBottomRight );
121
122       //foot of a perpendicular: (1,0) to the line
123       float footX1 = ( coefB*coefB - coefA*coefC) * inversedAABB;
124       float footY1 = (-coefA*coefB - coefB*coefC) * inversedAABB;
125       //foot of a perpendicular: (0,1) to the line
126       float footX2 = (-coefA*coefB - coefA*coefC) * inversedAABB;
127       float footY2 = ( coefA*coefA - coefB*coefC) * inversedAABB;
128       saddleParam[1] = (footX1-footX2)*(footX1-footX2) + (footY1-footY2)*(footY1-footY2);
129       translation = Vector2(-footX2,-footY2);
130     }
131     else
132     {
133       //distance from(1,0) to the line
134       float distanceTopRight = fabsf(coefA+coefC) * inversedSqrtAABB;
135       //distance from(0,1) to the line
136       float distanceBottomLeft = fabsf(coefB+coefC) * inversedSqrtAABB;
137       saddleA = std::max( distanceTopRight, distanceBottomLeft );
138       //foot of a perpendicular: (0,0) to the line
139       float footX3 = (-coefA*coefC) * inversedAABB;
140       float footY3 = (-coefB*coefC) * inversedAABB;
141       //foot of a perpendicular: (1.0,1.0) to the line
142       float footX4 = ( coefB*coefB - coefA*coefB - coefA*coefC) * inversedAABB;
143       float footY4 = (-coefA*coefB + coefA*coefA- coefB*coefC) * inversedAABB;
144       saddleParam[1] = (footX3-footX4)*(footX3-footX4) + (footY3-footY4)*(footY3-footY4);
145       translation = Vector2(-footX3, -footY3);
146     }
147
148     saddleParam[2] = sqrtf(saddleParam[1]);
149     saddleParam[0] = saddleA*saddleA;
150     rotation = Vector2(-displacement.x, displacement.y);
151     rotation.Normalize();
152
153     SafeSetCustomProperty( actor, "uSaddleParam", saddleParam );
154     SafeSetCustomProperty( actor, "uTranslation", translation );
155     SafeSetCustomProperty( actor, "uRotation", rotation );
156     SafeSetCustomProperty( actor, "uToNext", toNext );
157     SafeSetCustomProperty( actor, "uPercentage", initialProgress, Dali::Property::ANIMATABLE );
158 }
159 /**
160  * @brief Create a new Dissolve effect
161  *
162  *  DissolveEffect is a custom shader effect to achieve Dissolve effects in Image actors.
163  *
164  *  Animatable/Constrainable uniforms:
165  *    "uPercentage" - This value is proportional to the distortion applied; a value of zero means no distortion.
166  *
167  *  @param[in] useHighPrecision True if using high precision in fragment shader for fully random noise, false otherwise
168  *  @return The newly created Property::Map with the dissolve effect
169  */
170
171 inline Property::Map CreateDissolveEffect( bool useHighPrecision = true )
172 {
173   const char* prefixHighPrecision( "precision highp float;\n");
174   const char* prefixMediumPrecision( "precision mediump float;\n" );
175
176   const char* vertexShader( DALI_COMPOSE_SHADER(
177     attribute mediump vec2 aPosition;\n
178     \n
179     uniform mediump mat4 uMvpMatrix;\n
180     uniform vec3 uSize;\n
181     uniform vec4 uTextureRect;
182     \n
183     uniform float uPercentage;\n
184     uniform vec3 uSaddleParam;\n
185     uniform vec2 uTranslation;\n
186     uniform vec2 uRotation; \n
187     uniform float uToNext;\n
188     \n
189     varying float vPercentage;\n
190     varying vec2 vTexCoord;\n
191
192     void main()\n
193     {\n
194       mediump vec4 vertexPosition = vec4(aPosition, 0.0, 1.0);\n
195       vertexPosition.xyz *= uSize;\n
196       vertexPosition = uMvpMatrix * vertexPosition;\n
197       gl_Position = vertexPosition;\n
198
199       vec2 texCoord = aPosition + vec2(0.5);
200       vTexCoord = texCoord;\n
201       //Calculate the distortion value given the dissolve central line
202       vec2 value = texCoord + uTranslation; \n
203       mat2 rotateMatrix = mat2( uRotation.s, uRotation.t, -uRotation.t, uRotation.s ); \n
204       value = rotateMatrix * value; \n
205       if(uToNext == 1.0)  \n
206         value.s = uSaddleParam[2] + value.s; \n
207       float delay = value.t*value.t / uSaddleParam[0] - value.s*value.s/uSaddleParam[1];\n
208       vPercentage = clamp( uPercentage*2.0 - 0.5*sin(delay*1.571) - 0.5, 0.0, 1.0 ); \n
209     })
210   );
211
212   const char* fragmentShader( DALI_COMPOSE_SHADER(
213     varying float vPercentage;\n
214     varying mediump vec2 vTexCoord;\n
215     \n
216     uniform sampler2D sTexture;\n
217     uniform lowp vec4 uColor;\n
218     uniform vec4 uTextureRect;
219     \n
220     float rand(vec2 co) \n
221     {\n
222       return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453); \n
223     }\n
224     \n
225     void main()\n
226     {\n
227
228       //Calculate the randomness
229       float offsetS = rand( vTexCoord * vPercentage ) - vTexCoord.s; \n
230       float offsetT = rand( vec2(vTexCoord.t*vPercentage, vTexCoord.s * vPercentage) ) - vTexCoord.t; \n
231       vec2 lookupCoord = vTexCoord + vec2(offsetS, offsetT) * vPercentage; \n
232       gl_FragColor = texture2D( sTexture, lookupCoord ) * uColor; \n
233       gl_FragColor.a *= 1.0 - vPercentage; \n
234     } )
235   );
236
237   Property::Map map;
238
239   Property::Map customShader;
240
241   std::string vertexShaderString;
242   std::string fragmentShaderString;
243   if( useHighPrecision )
244   {
245     vertexShaderString.reserve(strlen( prefixHighPrecision ) + strlen( vertexShader ));
246     vertexShaderString.append( prefixHighPrecision );
247
248     fragmentShaderString.reserve(strlen( prefixHighPrecision ) + strlen( fragmentShader ));
249     fragmentShaderString.append( prefixHighPrecision );
250   }
251   else
252   {
253     vertexShaderString.reserve(strlen( prefixMediumPrecision ) + strlen( vertexShader ));
254     vertexShaderString.append( prefixMediumPrecision );
255
256     fragmentShaderString.reserve(strlen( prefixMediumPrecision ) + strlen( fragmentShader ));
257     fragmentShaderString.append( prefixMediumPrecision );
258   }
259
260   vertexShaderString.append( vertexShader );
261   fragmentShaderString.append( fragmentShader );
262
263   customShader[ "vertexShader" ] = vertexShaderString;
264   customShader[ "fragmentShader" ] = fragmentShaderString;
265
266   customShader[ "subdivideGridX" ] = 20;
267   customShader[ "subdivideGridY" ] = 20;
268
269   customShader[ "hints" ] = "outputIsTransparent";
270
271   map[ "shader" ] = customShader;
272   return map;
273 }
274
275 } // namespace Toolkit
276
277 } // namespace Dali
278
279 #endif // __DALI_TOOLKIT_SHADER_EFFECT_DISSOLVE_H__