[SRUK] Initial copy from Tizen 2.2 version
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / public-api / shader-effects / soft-button-effect.cpp
1 //
2 // Copyright (c) 2014 Samsung Electronics Co., Ltd.
3 //
4 // Licensed under the Flora License, Version 1.0 (the License);
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 //     http://floralicense.org/license/
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an AS IS BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 //
16
17 #include <dali-toolkit/public-api/shader-effects/soft-button-effect.h>
18 namespace Dali
19 {
20
21 namespace Toolkit
22 {
23
24 namespace
25 {
26
27 const std::string SOFT_BUTTON_LIGHTING_INDENTATION_AMOUNT_PROPERTY_NAME( "uLightingIndentationAmount" );
28 const std::string SOFT_BUTTON_TEXTURE_DISTORTION_AMOUNT_PROPERTY_NAME( "uTextureDistortAmount" );
29 const std::string SOFT_BUTTON_AMBIENT_LIGHT_AMOUNT_PROPERTY_NAME( "uAmbientLight" );
30 const std::string SOFT_BUTTON_DIFFUSE_LIGHT_PROPERTY_NAME( "uDiffuseLight" );
31 const std::string SOFT_BUTTON_LIGHTING_MULTIPLIER_PROPERTY_NAME( "uLightMultiplier" );
32 const std::string SOFT_BUTTON_INSIDE_SHAPE_SIZE_SCALE_PROPERTY_NAME( "uInsideCircleSizeScale" );
33 const std::string SOFT_BUTTON_RECIP_INSIDE_SHAPE_SIZE_SCALE_PROPERTY_NAME( "uRecipInsideCircleSizeScale" );
34 const std::string SOFT_BUTTON_OUTSIDE_SHAPE_DEPTH_PROPERTY_NAME( "uOutsideCircleDepth" );
35 const std::string SOFT_BUTTON_EFFECT_PIXEL_AREA_PROPERTY_NAME( "uEffectRegion" );
36 const std::string SOFT_BUTTON_RECTANGLE_SIZE_SCALE_PROPERTY_NAME( "uRectangleSizeScale" );
37
38
39 // factors that scale the look, defaults
40 const float SOFT_BUTTON_LIGHTING_INDENTATION_AMOUNT_DEFAULT = 0.0f;
41 const float SOFT_BUTTON_TEXTURE_DISTORTION_AMOUNT_DEFAULT = 0.0f;
42 const float SOFT_BUTTON_AMBIENT_LIGHT_AMOUNT_DEFAULT = 0.15f;
43 const Vector3 SOFT_BUTTON_DIFFUSE_LIGHT_DEFAULT = Vector3(0.0f, 0.7070168f, 0.7071068f);
44 const float SOFT_BUTTON_LIGHTING_MULTIPLIER_DEFAULT = 1.2f;
45 const float SOFT_BUTTON_INSIDE_SHAPE_SIZE_SCALE_DEFAULT = 0.75f;
46 const float SOFT_BUTTON_OUTSIDE_SHAPE_DEPTH_DEFAULT = Math::PI * 0.05f;
47 const Vector4 SOFT_BUTTON_EFFECT_PIXEL_AREA_DEFAULT = Vector4(0.0f, 0.0f, 1.0f, 1.0f);
48 const float SOFT_BUTTON_RECTANGLE_SIZE_SCALE_DEFAULT = 0.5f;
49
50 } // namespace
51
52 /**
53  * ReciprocalConstraint
54  *
55  * f(current, property) = 1.0 / property
56  */
57 struct ReciprocalConstraint
58 {
59   ReciprocalConstraint(){}
60
61   float operator()(const float current, const PropertyInput& property)
62   {
63     return 1.0f / property.GetFloat();
64   }
65 };
66
67
68 ////////////////////////////////////////////////////
69 //
70 // Soft button shader / actor tweaking parameters
71 //
72
73
74 SoftButtonEffect::SoftButtonEffect()
75 {
76 }
77
78 //Call the Parent copy constructor to add reference to the implementation for this object
79 SoftButtonEffect::SoftButtonEffect(ShaderEffect handle)
80 :ShaderEffect(handle)
81 {
82 }
83
84 SoftButtonEffect::~SoftButtonEffect()
85 {
86 }
87
88 SoftButtonEffect SoftButtonEffect::New(Type type)
89 {
90   std::string vertexSource;
91   vertexSource =  "precision mediump float;\n"
92     "uniform vec3 uDiffuseLight;\n"
93     "uniform float uAmbientLight;\n"
94     "uniform float uLightMultiplier;\n"
95     "uniform vec4 uEffectRegion;\n"
96     "varying vec2 vCentredCoord;\n"
97
98     "const vec3 norm = vec3(0.0, 0.0, 1.0);\n"
99
100     "void main()\n"
101     "{\n"
102     "  vTexCoord = aTexCoord;\n"
103     // Get the rect coords of the effect region in -1..1 range, i.e. circle centred around the center of the rect
104     // Done in the vertex shader itself to make use of gl interpolation for varying.
105     "  vCentredCoord = vec2( ( (vTexCoord.x - uEffectRegion.x)/(uEffectRegion.z - uEffectRegion.x) * 2.0 - 1.0 ), ( (vTexCoord.y - uEffectRegion.y)/(uEffectRegion.w - uEffectRegion.y) * 2.0 - 1.0  ) );\n"
106     "  gl_Position = uMvpMatrix * vec4(aPosition, 1.0);\n"
107     "}\n";
108
109   std::string fragmentSourceFixed;
110   fragmentSourceFixed =  "precision mediump float;\n"
111
112     "uniform vec3 uDiffuseLight;\n"
113     "uniform float uAmbientLight;\n"
114     "uniform float uLightMultiplier;\n"
115     "varying vec2 vCentredCoord;\n"
116
117     "const vec3 norm = vec3(0.0, 0.0, 1.0);\n"
118
119     "void main()\n"
120     "{\n"
121     "   vec4 col = texture2D(sTexture, vTexCoord);\n"
122     // calc lighting
123     "   float lighting = (dot(uDiffuseLight, norm) + uAmbientLight) * uLightMultiplier;\n"
124     // output col = image * light
125     // use the lighting value for colors only
126     "   gl_FragColor = vec4(col.rgb * uColor.rgb * lighting, col.a * uColor.a);\n"
127     "}\n";
128
129   std::string fragmentSourceElliptical;
130   fragmentSourceElliptical =  "precision mediump float;\n"
131
132     "uniform float uLightingIndentationAmount;\n"
133     "uniform float uTextureDistortAmount;\n"
134     "uniform vec3 uDiffuseLight;\n"
135     "uniform float uAmbientLight;\n"
136     "uniform float uLightMultiplier;\n"
137     "uniform float uInsideCircleSizeScale;\n"
138     "uniform float uRecipInsideCircleSizeScale;\n"
139     "uniform float uOutsideCircleDepth;\n"
140     "uniform vec4 uEffectRegion;\n"
141     "varying vec2 vCentredCoord;\n"
142
143     "const float PI = 3.1415927;\n"
144
145     "void main()\n"
146     "{\n"
147       // Apply distortion only if the pixel is within the rect specified
148       "if( (vTexCoord.x > uEffectRegion.x) && (vTexCoord.x < uEffectRegion.z) && (vTexCoord.y > uEffectRegion.y) && (vTexCoord.y < uEffectRegion.w) )\n"
149       "{\n"
150       "   vec2 coord = vCentredCoord;\n"
151
152       // find a coordinate representing distance from circle centre, such that we split into inside / outside circles that can have different gradients / normals
153       "   float realDistFromCentre = length(coord);\n"
154       "   realDistFromCentre = min(1.0, realDistFromCentre);\n" // clamp corners of square to vertical normal
155       "   float distFromCentre;\n"
156       "   if(realDistFromCentre <= uInsideCircleSizeScale)\n"
157       "   {\n"
158       "     distFromCentre = realDistFromCentre * uRecipInsideCircleSizeScale * (1.0 - uOutsideCircleDepth);\n" // inside circle indent, up to outline depth
159       "   }\n"
160       "   else                                                                                                                      \n"
161       "   {\n"
162       "     distFromCentre = mix(1.0 - uOutsideCircleDepth, 1.0, (realDistFromCentre - ( uInsideCircleSizeScale)) / (1.0 - uInsideCircleSizeScale));\n" // outside circle
163       "   }\n"
164
165       // get coords in -PI..PI range, i.e. scale the circle for use by trig functions
166       "  coord *= PI;\n"
167
168       // get a z value for the distorted surface in 0..1 range, using cos for a smooth curve (note, we ignore inside / outside circles since the difference isn't noticeable visually)
169       "   vec2 cosThetaCoord = (cos(coord) * 0.5) + 0.5;\n"
170       "   float z = cosThetaCoord.x * cosThetaCoord.y;\n"
171
172       // get the normal for the distorted surface, using the fact that the derivative of cos is -sin, finding tangent vector from slope and then normal by cross product...
173       "   float sinThetaCoord = sin(distFromCentre*PI) * uLightingIndentationAmount;\n" // slope, so tangent vec is (1.0, -sin)
174       // ...2D normal vector along distFromCentre vec is (sin, 1.0), convert to components in 3D.
175       "   vec3 norm = normalize(vec3(coord.x * sinThetaCoord, coord.y * sinThetaCoord, 1.0));\n"
176
177       // form surface z and project texture onto it.
178       "   float indentAmount = 1.0 / (1.0 - (z * uTextureDistortAmount));\n"
179       "   vec2 distortedCoord = vCentredCoord * indentAmount;\n"
180
181       // Convert the rect coordinates in -1 to 1 range back to the original coordinates
182       "   vec2 texCoord = vec2( ( (distortedCoord.x + 1.0)*(0.5) * (uEffectRegion.z - uEffectRegion.x) + uEffectRegion.x ), ( (distortedCoord.y + 1.0)*(0.5) * (uEffectRegion.w - uEffectRegion.y) + uEffectRegion.y  ) );  \n"
183       "   vec4 col = texture2D(sTexture, texCoord);\n"
184
185       // calc lighting
186       "   float lighting = (dot(uDiffuseLight, norm) + uAmbientLight) * uLightMultiplier;\n"
187       "  gl_FragColor = vec4(col.rgb * uColor.rgb * lighting, col.a * uColor.a);\n"
188       "}\n"
189       "else\n"
190       "{\n"
191       "  vec4 col = texture2D(sTexture, vTexCoord);\n"
192       "  float lighting = (dot(uDiffuseLight, vec3(0.0, 0.0, 1.0)) + uAmbientLight) * uLightMultiplier;\n"
193       "  gl_FragColor = vec4(col.rgb * uColor.rgb * lighting, col.a * uColor.a);\n"
194       "}\n"
195     "}\n";
196
197   std::string fragmentSourceRectangular;
198   fragmentSourceRectangular =  "precision mediump float;\n"
199
200     "uniform float uLightingIndentationAmount;\n"
201     "uniform float uTextureDistortAmount;\n"
202     "uniform vec3 uDiffuseLight;\n"
203     "uniform float uAmbientLight;\n"
204     "uniform float uLightMultiplier;\n"
205     "uniform float uInsideCircleSizeScale;\n"
206     "uniform float uRecipInsideCircleSizeScale;\n"
207     "uniform float uOutsideCircleDepth;\n"
208     "uniform float uRectangleSizeScale;\n"
209     "uniform vec4 uEffectRegion;\n"
210     "varying vec2 vCentredCoord;\n"
211
212     "const float PI = 3.1415927;\n"
213
214     "void main()\n"
215     "{\n"
216       // Apply distortion only if the pixel is within the rect specified
217       "if( (vTexCoord.x > uEffectRegion.x) && (vTexCoord.x < uEffectRegion.z) && (vTexCoord.y > uEffectRegion.y) && (vTexCoord.y < uEffectRegion.w) )\n"
218       "{ \n"
219         // get the rect coords to -1..1 range, i.e. circle centred around the center of the rect
220         "   vec2 centredCoord = vCentredCoord;\n"
221         // clamp coords such that the circle is split into 4 pieces that lie in the corners of the actor. uRectangleScale is the distance along each axis from the centre
222         // of the actor, e.g. 0.5 is half way along an axis from centre to actor edge.
223         "   vec2 clampedCoord;\n"
224         "   if(centredCoord.x > 0.0)\n"
225         "   {\n"
226         "     if(centredCoord.x < uRectangleSizeScale)\n"
227         "     {\n"
228                 // we are in a rectangular region along this axis, clamp coord to be same as centre pixel
229         "       clampedCoord.x = 0.0;\n"
230         "     }\n"
231         "     else\n"
232         "     {\n"
233                 // we are outside rectangular region along this axis, so we want curvature.
234         "       clampedCoord.x = smoothstep(0.0, 1.0, (centredCoord.x - uRectangleSizeScale) / (1.0 - uRectangleSizeScale));\n"
235         "     }\n"
236         "   }\n"
237         "   else\n"
238         "   {\n"
239         "     if(centredCoord.x > -uRectangleSizeScale)\n"
240         "     {\n"
241                 // we are in a rectangular region along this axis, clamp coord to be same as centre pixel
242         "       clampedCoord.x = 0.0;\n"
243         "     }\n"
244         "     else\n"
245         "     {\n"
246                 // we are outside rectangular region along this axis, so we want curvature.
247         "       clampedCoord.x = -smoothstep(0.0, 1.0, (centredCoord.x + uRectangleSizeScale) / (uRectangleSizeScale - 1.0));\n"
248         "     }\n"
249         "   }\n"
250         "   if(centredCoord.y > 0.0)\n"
251         "   {\n"
252         "     if(centredCoord.y < uRectangleSizeScale)\n"
253         "     {\n"
254                 // we are in a rectangular region along this axis, clamp coord to be same as centre pixel
255         "       clampedCoord.y = 0.0;\n"
256         "     }\n"
257         "     else\n"
258         "     {\n"
259                 // we are outside rectangular region along this axis, so we want curvature.
260         "       clampedCoord.y = smoothstep(0.0, 1.0, (centredCoord.y - uRectangleSizeScale) / (1.0 - uRectangleSizeScale));\n"
261         "     }\n"
262         "   }\n"
263         "   else\n"
264         "   {\n"
265         "     if(centredCoord.y > -uRectangleSizeScale)\n"
266         "     {\n"
267                 // we are in a rectangular region along this axis, clamp coord to be same as centre pixel
268         "       clampedCoord.y = 0.0;\n"
269         "     }\n"
270         "     else\n"
271         "     {\n"
272                 // we are outside rectangular region along this axis, so we want curvature.
273         "       clampedCoord.y = -smoothstep(0.0, 1.0, (centredCoord.y + uRectangleSizeScale) / (uRectangleSizeScale - 1.0));\n"
274         "     }\n"
275         "   }\n"
276         // get coords in -PI..PI range, i.e. scale above circle for use by trig functions
277         "   vec2 thetaCoord = clampedCoord * PI;\n"
278         // get a z value for the distorted surface in 0..1 range, using cos for a smooth curve (note, we ignore inside / outside circles since the difference isn't noticeable visually)
279         "   vec2 cosThetaCoord = (cos(thetaCoord) * 0.5) + 0.5;\n"
280         "   float z = cosThetaCoord.x * cosThetaCoord.y;\n"
281         // find a coordinate representing distance from circle centre, such that we split into inside / outside circles that can have different gradients / normals
282         "   float realDistFromCentre = length(thetaCoord);\n"
283         "   realDistFromCentre = min(PI, realDistFromCentre);\n" // clamp corners of square to vertical normal
284         "   float distFromCentre;\n"
285         "   if(realDistFromCentre <= PI * uInsideCircleSizeScale)\n"
286         "   {\n"
287         "     distFromCentre = realDistFromCentre * uRecipInsideCircleSizeScale * (PI - (uOutsideCircleDepth * PI)) / PI;\n" // inside circle indent, up to outline depth
288         "   }\n"
289         "   else\n"
290         "   {\n"
291         "     distFromCentre = mix(PI - (uOutsideCircleDepth * PI), PI, (realDistFromCentre - ( PI * uInsideCircleSizeScale)) / (PI - (PI * uInsideCircleSizeScale)));\n" // outside circle
292         "   }\n"
293         // get the normal for the distorted surface, using the fact that the derivative of cos is -sin, finding tangent vector from slope and then normal by cross product...
294         "   float sinThetaCoord = sin(distFromCentre) * uLightingIndentationAmount;\n" // slope, so tangent vec is (1.0, -sin)
295         // ...2D normal vector along distFromCentre vec is (sin, 1.0), convert to components in 3D.
296         "   vec3 norm = normalize(vec3(thetaCoord.x * sinThetaCoord, thetaCoord.y * sinThetaCoord, 1.0));\n"
297         // form surface z and project texture onto it.
298         "   float indentAmount = 1.0 / (1.0 - (z * uTextureDistortAmount));\n"
299         "   vec2 distortedCoord = centredCoord * indentAmount;\n"
300         // Convert the rect coordinates in -1 to 1 range back to the original coordinates
301         "   vec2 texCoord = vec2( ( (distortedCoord.x + 1.0)/(2.0) * (uEffectRegion.z - uEffectRegion.x) + uEffectRegion.x ), ( (distortedCoord.y + 1.0)/(2.0) * (uEffectRegion.w - uEffectRegion.y) + uEffectRegion.y  ) );\n"
302         "   vec4 col = texture2D(sTexture, texCoord);\n"
303         // calc lighting
304         "   float lighting = (dot(uDiffuseLight, norm) + uAmbientLight) * uLightMultiplier;\n"
305         // output col = image * light
306         // use the lighting value for colors only
307         "   gl_FragColor = vec4(col.rgb * uColor.rgb * lighting, col.a * uColor.a);\n"
308
309       "}\n"
310       "else\n"
311       "{\n"
312         "   vec4 col = texture2D(sTexture, vTexCoord);\n"
313         "   float lighting = (dot(uDiffuseLight, vec3(0.0, 0.0, 1.0)) + uAmbientLight) * uLightMultiplier;\n"
314         "   gl_FragColor = vec4(col.rgb * uColor.rgb * lighting, col.a * uColor.a);\n"
315       "} \n"
316     "}\n";
317
318
319   //////////////////////////////////////
320   // Create shader effect
321   //
322   //
323
324   ShaderEffect shader;
325   switch(type)
326   {
327     case RECTANGULAR:
328       shader = ShaderEffect::New( vertexSource, fragmentSourceRectangular, GeometryType( GEOMETRY_TYPE_IMAGE ), ShaderEffect::GeometryHints( ShaderEffect::HINT_NONE ));
329       break;
330
331     case ELLIPTICAL:
332       shader = ShaderEffect::New( vertexSource, fragmentSourceElliptical, GeometryType( GEOMETRY_TYPE_IMAGE ), ShaderEffect::GeometryHints( ShaderEffect::HINT_NONE ));
333       break;
334
335     case FIXED:
336     default:
337       shader = ShaderEffect::New( vertexSource, fragmentSourceFixed, GeometryType( GEOMETRY_TYPE_IMAGE ), ShaderEffect::GeometryHints( ShaderEffect::HINT_NONE ));
338       break;
339   }
340   SoftButtonEffect handle( shader );
341
342
343   //////////////////////////////////////
344   // Register uniform properties
345   //
346   //
347
348   // factors that scale the look, defaults
349   handle.SetUniform(SOFT_BUTTON_AMBIENT_LIGHT_AMOUNT_PROPERTY_NAME, SOFT_BUTTON_AMBIENT_LIGHT_AMOUNT_DEFAULT);
350   handle.SetUniform(SOFT_BUTTON_DIFFUSE_LIGHT_PROPERTY_NAME, SOFT_BUTTON_DIFFUSE_LIGHT_DEFAULT);
351   handle.SetUniform(SOFT_BUTTON_LIGHTING_MULTIPLIER_PROPERTY_NAME, SOFT_BUTTON_LIGHTING_MULTIPLIER_DEFAULT);
352   if(FIXED != type)
353   {
354     handle.SetUniform(SOFT_BUTTON_LIGHTING_INDENTATION_AMOUNT_PROPERTY_NAME, SOFT_BUTTON_LIGHTING_INDENTATION_AMOUNT_DEFAULT);
355     handle.SetUniform(SOFT_BUTTON_TEXTURE_DISTORTION_AMOUNT_PROPERTY_NAME, SOFT_BUTTON_TEXTURE_DISTORTION_AMOUNT_DEFAULT);
356     handle.SetUniform(SOFT_BUTTON_INSIDE_SHAPE_SIZE_SCALE_PROPERTY_NAME, SOFT_BUTTON_INSIDE_SHAPE_SIZE_SCALE_DEFAULT);
357     handle.SetUniform(SOFT_BUTTON_RECIP_INSIDE_SHAPE_SIZE_SCALE_PROPERTY_NAME, 1.0f / SOFT_BUTTON_INSIDE_SHAPE_SIZE_SCALE_DEFAULT);
358     handle.SetUniform(SOFT_BUTTON_OUTSIDE_SHAPE_DEPTH_PROPERTY_NAME, SOFT_BUTTON_OUTSIDE_SHAPE_DEPTH_DEFAULT);
359     handle.SetUniform(SOFT_BUTTON_EFFECT_PIXEL_AREA_PROPERTY_NAME, SOFT_BUTTON_EFFECT_PIXEL_AREA_DEFAULT);
360     if(RECTANGULAR == type)
361     {
362       handle.SetUniform(SOFT_BUTTON_RECTANGLE_SIZE_SCALE_PROPERTY_NAME, SOFT_BUTTON_RECTANGLE_SIZE_SCALE_DEFAULT);
363     }
364
365     // precalc 1.0 / uInsideCircleSizeScale on CPU to save shader insns, using constraint to tie to the normal property
366     Property::Index insideCircleSizeScalePropertyIndex = handle.GetPropertyIndex(SOFT_BUTTON_INSIDE_SHAPE_SIZE_SCALE_PROPERTY_NAME);
367     Property::Index recipInsideCircleSizeScalePropertyIndex = handle.GetPropertyIndex(SOFT_BUTTON_RECIP_INSIDE_SHAPE_SIZE_SCALE_PROPERTY_NAME);
368     Constraint constraint = Constraint::New<float>( recipInsideCircleSizeScalePropertyIndex, LocalSource(insideCircleSizeScalePropertyIndex), ReciprocalConstraint());
369     handle.ApplyConstraint(constraint);
370   }
371
372   return handle;
373 }
374
375 const std::string& SoftButtonEffect::GetLightingIndentationAmountPropertyName() const
376 {
377   return SOFT_BUTTON_LIGHTING_INDENTATION_AMOUNT_PROPERTY_NAME;
378 }
379
380 const std::string& SoftButtonEffect::GetTextureDistortionAmountPropertyName() const
381 {
382   return SOFT_BUTTON_TEXTURE_DISTORTION_AMOUNT_PROPERTY_NAME;
383 }
384
385 const std::string& SoftButtonEffect::GetAmbientLightAmountPropertyName() const
386 {
387   return SOFT_BUTTON_AMBIENT_LIGHT_AMOUNT_PROPERTY_NAME;
388 }
389
390 const std::string& SoftButtonEffect::GetDiffuseLightPropertyName() const
391 {
392   return SOFT_BUTTON_DIFFUSE_LIGHT_PROPERTY_NAME;
393 }
394
395 const std::string& SoftButtonEffect::GetLightingMultiplierPropertyName() const
396 {
397   return SOFT_BUTTON_LIGHTING_MULTIPLIER_PROPERTY_NAME;
398 }
399
400 const std::string& SoftButtonEffect::GetInsideShapeSizeScalePropertyName() const
401 {
402   return SOFT_BUTTON_INSIDE_SHAPE_SIZE_SCALE_PROPERTY_NAME;
403 }
404
405 const std::string& SoftButtonEffect::GetOutsideShapeDepthPropertyName() const
406 {
407   return SOFT_BUTTON_OUTSIDE_SHAPE_DEPTH_PROPERTY_NAME;
408 }
409
410 const std::string& SoftButtonEffect::GetEffectPixelAreaPropertyName() const
411 {
412   return SOFT_BUTTON_EFFECT_PIXEL_AREA_PROPERTY_NAME;
413 }
414
415 const std::string& SoftButtonEffect::GetRectangleSizeScalePropertyName() const
416 {
417   return SOFT_BUTTON_RECTANGLE_SIZE_SCALE_PROPERTY_NAME;
418 }
419
420 }
421
422 }
423