2 * Copyright (c) 2014 Samsung Electronics Co., Ltd.
4 * Licensed under the Apache License, Version 2.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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 #include <dali/public-api/animation/active-constraint.h>
20 #include <dali/public-api/animation/constraint.h>
21 #include <dali/public-api/object/property-input.h>
24 #include <dali-toolkit/public-api/shader-effects/soft-button-effect.h>
35 const std::string SOFT_BUTTON_LIGHTING_INDENTATION_AMOUNT_PROPERTY_NAME( "uLightingIndentationAmount" );
36 const std::string SOFT_BUTTON_TEXTURE_DISTORTION_AMOUNT_PROPERTY_NAME( "uTextureDistortAmount" );
37 const std::string SOFT_BUTTON_AMBIENT_LIGHT_AMOUNT_PROPERTY_NAME( "uAmbientLight" );
38 const std::string SOFT_BUTTON_DIFFUSE_LIGHT_PROPERTY_NAME( "uDiffuseLight" );
39 const std::string SOFT_BUTTON_LIGHTING_MULTIPLIER_PROPERTY_NAME( "uLightMultiplier" );
40 const std::string SOFT_BUTTON_INSIDE_SHAPE_SIZE_SCALE_PROPERTY_NAME( "uInsideCircleSizeScale" );
41 const std::string SOFT_BUTTON_RECIP_INSIDE_SHAPE_SIZE_SCALE_PROPERTY_NAME( "uRecipInsideCircleSizeScale" );
42 const std::string SOFT_BUTTON_OUTSIDE_SHAPE_DEPTH_PROPERTY_NAME( "uOutsideCircleDepth" );
43 const std::string SOFT_BUTTON_EFFECT_PIXEL_AREA_PROPERTY_NAME( "uEffectRegion" );
44 const std::string SOFT_BUTTON_RECTANGLE_SIZE_SCALE_PROPERTY_NAME( "uRectangleSizeScale" );
47 // factors that scale the look, defaults
48 const float SOFT_BUTTON_LIGHTING_INDENTATION_AMOUNT_DEFAULT = 0.0f;
49 const float SOFT_BUTTON_TEXTURE_DISTORTION_AMOUNT_DEFAULT = 0.0f;
50 const float SOFT_BUTTON_AMBIENT_LIGHT_AMOUNT_DEFAULT = 0.15f;
51 const Vector3 SOFT_BUTTON_DIFFUSE_LIGHT_DEFAULT = Vector3(0.0f, 0.7070168f, 0.7071068f);
52 const float SOFT_BUTTON_LIGHTING_MULTIPLIER_DEFAULT = 1.2f;
53 const float SOFT_BUTTON_INSIDE_SHAPE_SIZE_SCALE_DEFAULT = 0.75f;
54 const float SOFT_BUTTON_OUTSIDE_SHAPE_DEPTH_DEFAULT = Math::PI * 0.05f;
55 const Vector4 SOFT_BUTTON_EFFECT_PIXEL_AREA_DEFAULT = Vector4(0.0f, 0.0f, 1.0f, 1.0f);
56 const float SOFT_BUTTON_RECTANGLE_SIZE_SCALE_DEFAULT = 0.5f;
61 * ReciprocalConstraint
63 * f(current, property) = 1.0 / property
65 struct ReciprocalConstraint
67 ReciprocalConstraint(){}
69 float operator()(const float current, const PropertyInput& property)
71 return 1.0f / property.GetFloat();
76 ////////////////////////////////////////////////////
78 // Soft button shader / actor tweaking parameters
82 SoftButtonEffect::SoftButtonEffect()
86 //Call the Parent copy constructor to add reference to the implementation for this object
87 SoftButtonEffect::SoftButtonEffect(ShaderEffect handle)
92 SoftButtonEffect::~SoftButtonEffect()
96 SoftButtonEffect SoftButtonEffect::New(Type type)
98 std::string vertexSource;
99 vertexSource = "precision mediump float;\n"
100 "uniform vec3 uDiffuseLight;\n"
101 "uniform float uAmbientLight;\n"
102 "uniform float uLightMultiplier;\n"
103 "uniform vec4 uEffectRegion;\n"
104 "varying vec2 vCentredCoord;\n"
106 "const vec3 norm = vec3(0.0, 0.0, 1.0);\n"
110 " vTexCoord = aTexCoord;\n"
111 // Get the rect coords of the effect region in -1..1 range, i.e. circle centred around the center of the rect
112 // Done in the vertex shader itself to make use of gl interpolation for varying.
113 " 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"
114 " gl_Position = uMvpMatrix * vec4(aPosition, 1.0);\n"
117 std::string fragmentSourceFixed;
118 fragmentSourceFixed = "precision mediump float;\n"
120 "uniform vec3 uDiffuseLight;\n"
121 "uniform float uAmbientLight;\n"
122 "uniform float uLightMultiplier;\n"
123 "varying vec2 vCentredCoord;\n"
125 "const vec3 norm = vec3(0.0, 0.0, 1.0);\n"
129 " vec4 col = texture2D(sTexture, vTexCoord);\n"
131 " float lighting = (dot(uDiffuseLight, norm) + uAmbientLight) * uLightMultiplier;\n"
132 // output col = image * light
133 // use the lighting value for colors only
134 " gl_FragColor = vec4(col.rgb * uColor.rgb * lighting, col.a * uColor.a);\n"
137 std::string fragmentSourceElliptical;
138 fragmentSourceElliptical = "precision mediump float;\n"
140 "uniform float uLightingIndentationAmount;\n"
141 "uniform float uTextureDistortAmount;\n"
142 "uniform vec3 uDiffuseLight;\n"
143 "uniform float uAmbientLight;\n"
144 "uniform float uLightMultiplier;\n"
145 "uniform float uInsideCircleSizeScale;\n"
146 "uniform float uRecipInsideCircleSizeScale;\n"
147 "uniform float uOutsideCircleDepth;\n"
148 "uniform vec4 uEffectRegion;\n"
149 "varying vec2 vCentredCoord;\n"
151 "const float PI = 3.1415927;\n"
155 // Apply distortion only if the pixel is within the rect specified
156 "if( (vTexCoord.x > uEffectRegion.x) && (vTexCoord.x < uEffectRegion.z) && (vTexCoord.y > uEffectRegion.y) && (vTexCoord.y < uEffectRegion.w) )\n"
158 " vec2 coord = vCentredCoord;\n"
160 // find a coordinate representing distance from circle centre, such that we split into inside / outside circles that can have different gradients / normals
161 " float realDistFromCentre = length(coord);\n"
162 " realDistFromCentre = min(1.0, realDistFromCentre);\n" // clamp corners of square to vertical normal
163 " float distFromCentre;\n"
164 " if(realDistFromCentre <= uInsideCircleSizeScale)\n"
166 " distFromCentre = realDistFromCentre * uRecipInsideCircleSizeScale * (1.0 - uOutsideCircleDepth);\n" // inside circle indent, up to outline depth
170 " distFromCentre = mix(1.0 - uOutsideCircleDepth, 1.0, (realDistFromCentre - ( uInsideCircleSizeScale)) / (1.0 - uInsideCircleSizeScale));\n" // outside circle
173 // get coords in -PI..PI range, i.e. scale the circle for use by trig functions
176 // 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)
177 " vec2 cosThetaCoord = (cos(coord) * 0.5) + 0.5;\n"
178 " float z = cosThetaCoord.x * cosThetaCoord.y;\n"
180 // 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...
181 " float sinThetaCoord = sin(distFromCentre*PI) * uLightingIndentationAmount;\n" // slope, so tangent vec is (1.0, -sin)
182 // ...2D normal vector along distFromCentre vec is (sin, 1.0), convert to components in 3D.
183 " vec3 norm = normalize(vec3(coord.x * sinThetaCoord, coord.y * sinThetaCoord, 1.0));\n"
185 // form surface z and project texture onto it.
186 " float indentAmount = 1.0 / (1.0 - (z * uTextureDistortAmount));\n"
187 " vec2 distortedCoord = vCentredCoord * indentAmount;\n"
189 // Convert the rect coordinates in -1 to 1 range back to the original coordinates
190 " 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"
191 " vec4 col = texture2D(sTexture, texCoord);\n"
194 " float lighting = (dot(uDiffuseLight, norm) + uAmbientLight) * uLightMultiplier;\n"
195 " gl_FragColor = vec4(col.rgb * uColor.rgb * lighting, col.a * uColor.a);\n"
199 " vec4 col = texture2D(sTexture, vTexCoord);\n"
200 " float lighting = (dot(uDiffuseLight, vec3(0.0, 0.0, 1.0)) + uAmbientLight) * uLightMultiplier;\n"
201 " gl_FragColor = vec4(col.rgb * uColor.rgb * lighting, col.a * uColor.a);\n"
205 std::string fragmentSourceRectangular;
206 fragmentSourceRectangular = "precision mediump float;\n"
208 "uniform float uLightingIndentationAmount;\n"
209 "uniform float uTextureDistortAmount;\n"
210 "uniform vec3 uDiffuseLight;\n"
211 "uniform float uAmbientLight;\n"
212 "uniform float uLightMultiplier;\n"
213 "uniform float uInsideCircleSizeScale;\n"
214 "uniform float uRecipInsideCircleSizeScale;\n"
215 "uniform float uOutsideCircleDepth;\n"
216 "uniform float uRectangleSizeScale;\n"
217 "uniform vec4 uEffectRegion;\n"
218 "varying vec2 vCentredCoord;\n"
220 "const float PI = 3.1415927;\n"
224 // Apply distortion only if the pixel is within the rect specified
225 "if( (vTexCoord.x > uEffectRegion.x) && (vTexCoord.x < uEffectRegion.z) && (vTexCoord.y > uEffectRegion.y) && (vTexCoord.y < uEffectRegion.w) )\n"
227 // get the rect coords to -1..1 range, i.e. circle centred around the center of the rect
228 " vec2 centredCoord = vCentredCoord;\n"
229 // 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
230 // of the actor, e.g. 0.5 is half way along an axis from centre to actor edge.
231 " vec2 clampedCoord;\n"
232 " if(centredCoord.x > 0.0)\n"
234 " if(centredCoord.x < uRectangleSizeScale)\n"
236 // we are in a rectangular region along this axis, clamp coord to be same as centre pixel
237 " clampedCoord.x = 0.0;\n"
241 // we are outside rectangular region along this axis, so we want curvature.
242 " clampedCoord.x = smoothstep(0.0, 1.0, (centredCoord.x - uRectangleSizeScale) / (1.0 - uRectangleSizeScale));\n"
247 " if(centredCoord.x > -uRectangleSizeScale)\n"
249 // we are in a rectangular region along this axis, clamp coord to be same as centre pixel
250 " clampedCoord.x = 0.0;\n"
254 // we are outside rectangular region along this axis, so we want curvature.
255 " clampedCoord.x = -smoothstep(0.0, 1.0, (centredCoord.x + uRectangleSizeScale) / (uRectangleSizeScale - 1.0));\n"
258 " if(centredCoord.y > 0.0)\n"
260 " if(centredCoord.y < uRectangleSizeScale)\n"
262 // we are in a rectangular region along this axis, clamp coord to be same as centre pixel
263 " clampedCoord.y = 0.0;\n"
267 // we are outside rectangular region along this axis, so we want curvature.
268 " clampedCoord.y = smoothstep(0.0, 1.0, (centredCoord.y - uRectangleSizeScale) / (1.0 - uRectangleSizeScale));\n"
273 " if(centredCoord.y > -uRectangleSizeScale)\n"
275 // we are in a rectangular region along this axis, clamp coord to be same as centre pixel
276 " clampedCoord.y = 0.0;\n"
280 // we are outside rectangular region along this axis, so we want curvature.
281 " clampedCoord.y = -smoothstep(0.0, 1.0, (centredCoord.y + uRectangleSizeScale) / (uRectangleSizeScale - 1.0));\n"
284 // get coords in -PI..PI range, i.e. scale above circle for use by trig functions
285 " vec2 thetaCoord = clampedCoord * PI;\n"
286 // 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)
287 " vec2 cosThetaCoord = (cos(thetaCoord) * 0.5) + 0.5;\n"
288 " float z = cosThetaCoord.x * cosThetaCoord.y;\n"
289 // find a coordinate representing distance from circle centre, such that we split into inside / outside circles that can have different gradients / normals
290 " float realDistFromCentre = length(thetaCoord);\n"
291 " realDistFromCentre = min(PI, realDistFromCentre);\n" // clamp corners of square to vertical normal
292 " float distFromCentre;\n"
293 " if(realDistFromCentre <= PI * uInsideCircleSizeScale)\n"
295 " distFromCentre = realDistFromCentre * uRecipInsideCircleSizeScale * (PI - (uOutsideCircleDepth * PI)) / PI;\n" // inside circle indent, up to outline depth
299 " distFromCentre = mix(PI - (uOutsideCircleDepth * PI), PI, (realDistFromCentre - ( PI * uInsideCircleSizeScale)) / (PI - (PI * uInsideCircleSizeScale)));\n" // outside circle
301 // 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...
302 " float sinThetaCoord = sin(distFromCentre) * uLightingIndentationAmount;\n" // slope, so tangent vec is (1.0, -sin)
303 // ...2D normal vector along distFromCentre vec is (sin, 1.0), convert to components in 3D.
304 " vec3 norm = normalize(vec3(thetaCoord.x * sinThetaCoord, thetaCoord.y * sinThetaCoord, 1.0));\n"
305 // form surface z and project texture onto it.
306 " float indentAmount = 1.0 / (1.0 - (z * uTextureDistortAmount));\n"
307 " vec2 distortedCoord = centredCoord * indentAmount;\n"
308 // Convert the rect coordinates in -1 to 1 range back to the original coordinates
309 " 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"
310 " vec4 col = texture2D(sTexture, texCoord);\n"
312 " float lighting = (dot(uDiffuseLight, norm) + uAmbientLight) * uLightMultiplier;\n"
313 // output col = image * light
314 // use the lighting value for colors only
315 " gl_FragColor = vec4(col.rgb * uColor.rgb * lighting, col.a * uColor.a);\n"
320 " vec4 col = texture2D(sTexture, vTexCoord);\n"
321 " float lighting = (dot(uDiffuseLight, vec3(0.0, 0.0, 1.0)) + uAmbientLight) * uLightMultiplier;\n"
322 " gl_FragColor = vec4(col.rgb * uColor.rgb * lighting, col.a * uColor.a);\n"
327 //////////////////////////////////////
328 // Create shader effect
336 shader = ShaderEffect::New( vertexSource, fragmentSourceRectangular, GeometryType( GEOMETRY_TYPE_IMAGE ), ShaderEffect::GeometryHints( ShaderEffect::HINT_NONE ));
340 shader = ShaderEffect::New( vertexSource, fragmentSourceElliptical, GeometryType( GEOMETRY_TYPE_IMAGE ), ShaderEffect::GeometryHints( ShaderEffect::HINT_NONE ));
345 shader = ShaderEffect::New( vertexSource, fragmentSourceFixed, GeometryType( GEOMETRY_TYPE_IMAGE ), ShaderEffect::GeometryHints( ShaderEffect::HINT_NONE ));
348 SoftButtonEffect handle( shader );
351 //////////////////////////////////////
352 // Register uniform properties
356 // factors that scale the look, defaults
357 handle.SetUniform(SOFT_BUTTON_AMBIENT_LIGHT_AMOUNT_PROPERTY_NAME, SOFT_BUTTON_AMBIENT_LIGHT_AMOUNT_DEFAULT);
358 handle.SetUniform(SOFT_BUTTON_DIFFUSE_LIGHT_PROPERTY_NAME, SOFT_BUTTON_DIFFUSE_LIGHT_DEFAULT);
359 handle.SetUniform(SOFT_BUTTON_LIGHTING_MULTIPLIER_PROPERTY_NAME, SOFT_BUTTON_LIGHTING_MULTIPLIER_DEFAULT);
362 handle.SetUniform(SOFT_BUTTON_LIGHTING_INDENTATION_AMOUNT_PROPERTY_NAME, SOFT_BUTTON_LIGHTING_INDENTATION_AMOUNT_DEFAULT);
363 handle.SetUniform(SOFT_BUTTON_TEXTURE_DISTORTION_AMOUNT_PROPERTY_NAME, SOFT_BUTTON_TEXTURE_DISTORTION_AMOUNT_DEFAULT);
364 handle.SetUniform(SOFT_BUTTON_INSIDE_SHAPE_SIZE_SCALE_PROPERTY_NAME, SOFT_BUTTON_INSIDE_SHAPE_SIZE_SCALE_DEFAULT);
365 handle.SetUniform(SOFT_BUTTON_RECIP_INSIDE_SHAPE_SIZE_SCALE_PROPERTY_NAME, 1.0f / SOFT_BUTTON_INSIDE_SHAPE_SIZE_SCALE_DEFAULT);
366 handle.SetUniform(SOFT_BUTTON_OUTSIDE_SHAPE_DEPTH_PROPERTY_NAME, SOFT_BUTTON_OUTSIDE_SHAPE_DEPTH_DEFAULT);
367 handle.SetUniform(SOFT_BUTTON_EFFECT_PIXEL_AREA_PROPERTY_NAME, SOFT_BUTTON_EFFECT_PIXEL_AREA_DEFAULT);
368 if(RECTANGULAR == type)
370 handle.SetUniform(SOFT_BUTTON_RECTANGLE_SIZE_SCALE_PROPERTY_NAME, SOFT_BUTTON_RECTANGLE_SIZE_SCALE_DEFAULT);
373 // precalc 1.0 / uInsideCircleSizeScale on CPU to save shader insns, using constraint to tie to the normal property
374 Dali::Property::Index insideCircleSizeScalePropertyIndex = handle.GetPropertyIndex(SOFT_BUTTON_INSIDE_SHAPE_SIZE_SCALE_PROPERTY_NAME);
375 Dali::Property::Index recipInsideCircleSizeScalePropertyIndex = handle.GetPropertyIndex(SOFT_BUTTON_RECIP_INSIDE_SHAPE_SIZE_SCALE_PROPERTY_NAME);
376 Constraint constraint = Constraint::New<float>( recipInsideCircleSizeScalePropertyIndex, LocalSource(insideCircleSizeScalePropertyIndex), ReciprocalConstraint());
377 handle.ApplyConstraint(constraint);
383 const std::string& SoftButtonEffect::GetLightingIndentationAmountPropertyName() const
385 return SOFT_BUTTON_LIGHTING_INDENTATION_AMOUNT_PROPERTY_NAME;
388 const std::string& SoftButtonEffect::GetTextureDistortionAmountPropertyName() const
390 return SOFT_BUTTON_TEXTURE_DISTORTION_AMOUNT_PROPERTY_NAME;
393 const std::string& SoftButtonEffect::GetAmbientLightAmountPropertyName() const
395 return SOFT_BUTTON_AMBIENT_LIGHT_AMOUNT_PROPERTY_NAME;
398 const std::string& SoftButtonEffect::GetDiffuseLightPropertyName() const
400 return SOFT_BUTTON_DIFFUSE_LIGHT_PROPERTY_NAME;
403 const std::string& SoftButtonEffect::GetLightingMultiplierPropertyName() const
405 return SOFT_BUTTON_LIGHTING_MULTIPLIER_PROPERTY_NAME;
408 const std::string& SoftButtonEffect::GetInsideShapeSizeScalePropertyName() const
410 return SOFT_BUTTON_INSIDE_SHAPE_SIZE_SCALE_PROPERTY_NAME;
413 const std::string& SoftButtonEffect::GetOutsideShapeDepthPropertyName() const
415 return SOFT_BUTTON_OUTSIDE_SHAPE_DEPTH_PROPERTY_NAME;
418 const std::string& SoftButtonEffect::GetEffectPixelAreaPropertyName() const
420 return SOFT_BUTTON_EFFECT_PIXEL_AREA_PROPERTY_NAME;
423 const std::string& SoftButtonEffect::GetRectangleSizeScalePropertyName() const
425 return SOFT_BUTTON_RECTANGLE_SIZE_SCALE_PROPERTY_NAME;