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.
18 #include <dali-toolkit/public-api/shader-effects/soft-button-effect.h>
28 const std::string SOFT_BUTTON_LIGHTING_INDENTATION_AMOUNT_PROPERTY_NAME( "uLightingIndentationAmount" );
29 const std::string SOFT_BUTTON_TEXTURE_DISTORTION_AMOUNT_PROPERTY_NAME( "uTextureDistortAmount" );
30 const std::string SOFT_BUTTON_AMBIENT_LIGHT_AMOUNT_PROPERTY_NAME( "uAmbientLight" );
31 const std::string SOFT_BUTTON_DIFFUSE_LIGHT_PROPERTY_NAME( "uDiffuseLight" );
32 const std::string SOFT_BUTTON_LIGHTING_MULTIPLIER_PROPERTY_NAME( "uLightMultiplier" );
33 const std::string SOFT_BUTTON_INSIDE_SHAPE_SIZE_SCALE_PROPERTY_NAME( "uInsideCircleSizeScale" );
34 const std::string SOFT_BUTTON_RECIP_INSIDE_SHAPE_SIZE_SCALE_PROPERTY_NAME( "uRecipInsideCircleSizeScale" );
35 const std::string SOFT_BUTTON_OUTSIDE_SHAPE_DEPTH_PROPERTY_NAME( "uOutsideCircleDepth" );
36 const std::string SOFT_BUTTON_EFFECT_PIXEL_AREA_PROPERTY_NAME( "uEffectRegion" );
37 const std::string SOFT_BUTTON_RECTANGLE_SIZE_SCALE_PROPERTY_NAME( "uRectangleSizeScale" );
40 // factors that scale the look, defaults
41 const float SOFT_BUTTON_LIGHTING_INDENTATION_AMOUNT_DEFAULT = 0.0f;
42 const float SOFT_BUTTON_TEXTURE_DISTORTION_AMOUNT_DEFAULT = 0.0f;
43 const float SOFT_BUTTON_AMBIENT_LIGHT_AMOUNT_DEFAULT = 0.15f;
44 const Vector3 SOFT_BUTTON_DIFFUSE_LIGHT_DEFAULT = Vector3(0.0f, 0.7070168f, 0.7071068f);
45 const float SOFT_BUTTON_LIGHTING_MULTIPLIER_DEFAULT = 1.2f;
46 const float SOFT_BUTTON_INSIDE_SHAPE_SIZE_SCALE_DEFAULT = 0.75f;
47 const float SOFT_BUTTON_OUTSIDE_SHAPE_DEPTH_DEFAULT = Math::PI * 0.05f;
48 const Vector4 SOFT_BUTTON_EFFECT_PIXEL_AREA_DEFAULT = Vector4(0.0f, 0.0f, 1.0f, 1.0f);
49 const float SOFT_BUTTON_RECTANGLE_SIZE_SCALE_DEFAULT = 0.5f;
54 * ReciprocalConstraint
56 * f(current, property) = 1.0 / property
58 struct ReciprocalConstraint
60 ReciprocalConstraint(){}
62 float operator()(const float current, const PropertyInput& property)
64 return 1.0f / property.GetFloat();
69 ////////////////////////////////////////////////////
71 // Soft button shader / actor tweaking parameters
75 SoftButtonEffect::SoftButtonEffect()
79 //Call the Parent copy constructor to add reference to the implementation for this object
80 SoftButtonEffect::SoftButtonEffect(ShaderEffect handle)
85 SoftButtonEffect::~SoftButtonEffect()
89 SoftButtonEffect SoftButtonEffect::New(Type type)
91 std::string vertexSource;
92 vertexSource = "precision mediump float;\n"
93 "uniform vec3 uDiffuseLight;\n"
94 "uniform float uAmbientLight;\n"
95 "uniform float uLightMultiplier;\n"
96 "uniform vec4 uEffectRegion;\n"
97 "varying vec2 vCentredCoord;\n"
99 "const vec3 norm = vec3(0.0, 0.0, 1.0);\n"
103 " vTexCoord = aTexCoord;\n"
104 // Get the rect coords of the effect region in -1..1 range, i.e. circle centred around the center of the rect
105 // Done in the vertex shader itself to make use of gl interpolation for varying.
106 " 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"
107 " gl_Position = uMvpMatrix * vec4(aPosition, 1.0);\n"
110 std::string fragmentSourceFixed;
111 fragmentSourceFixed = "precision mediump float;\n"
113 "uniform vec3 uDiffuseLight;\n"
114 "uniform float uAmbientLight;\n"
115 "uniform float uLightMultiplier;\n"
116 "varying vec2 vCentredCoord;\n"
118 "const vec3 norm = vec3(0.0, 0.0, 1.0);\n"
122 " vec4 col = texture2D(sTexture, vTexCoord);\n"
124 " float lighting = (dot(uDiffuseLight, norm) + uAmbientLight) * uLightMultiplier;\n"
125 // output col = image * light
126 // use the lighting value for colors only
127 " gl_FragColor = vec4(col.rgb * uColor.rgb * lighting, col.a * uColor.a);\n"
130 std::string fragmentSourceElliptical;
131 fragmentSourceElliptical = "precision mediump float;\n"
133 "uniform float uLightingIndentationAmount;\n"
134 "uniform float uTextureDistortAmount;\n"
135 "uniform vec3 uDiffuseLight;\n"
136 "uniform float uAmbientLight;\n"
137 "uniform float uLightMultiplier;\n"
138 "uniform float uInsideCircleSizeScale;\n"
139 "uniform float uRecipInsideCircleSizeScale;\n"
140 "uniform float uOutsideCircleDepth;\n"
141 "uniform vec4 uEffectRegion;\n"
142 "varying vec2 vCentredCoord;\n"
144 "const float PI = 3.1415927;\n"
148 // Apply distortion only if the pixel is within the rect specified
149 "if( (vTexCoord.x > uEffectRegion.x) && (vTexCoord.x < uEffectRegion.z) && (vTexCoord.y > uEffectRegion.y) && (vTexCoord.y < uEffectRegion.w) )\n"
151 " vec2 coord = vCentredCoord;\n"
153 // find a coordinate representing distance from circle centre, such that we split into inside / outside circles that can have different gradients / normals
154 " float realDistFromCentre = length(coord);\n"
155 " realDistFromCentre = min(1.0, realDistFromCentre);\n" // clamp corners of square to vertical normal
156 " float distFromCentre;\n"
157 " if(realDistFromCentre <= uInsideCircleSizeScale)\n"
159 " distFromCentre = realDistFromCentre * uRecipInsideCircleSizeScale * (1.0 - uOutsideCircleDepth);\n" // inside circle indent, up to outline depth
163 " distFromCentre = mix(1.0 - uOutsideCircleDepth, 1.0, (realDistFromCentre - ( uInsideCircleSizeScale)) / (1.0 - uInsideCircleSizeScale));\n" // outside circle
166 // get coords in -PI..PI range, i.e. scale the circle for use by trig functions
169 // 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)
170 " vec2 cosThetaCoord = (cos(coord) * 0.5) + 0.5;\n"
171 " float z = cosThetaCoord.x * cosThetaCoord.y;\n"
173 // 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...
174 " float sinThetaCoord = sin(distFromCentre*PI) * uLightingIndentationAmount;\n" // slope, so tangent vec is (1.0, -sin)
175 // ...2D normal vector along distFromCentre vec is (sin, 1.0), convert to components in 3D.
176 " vec3 norm = normalize(vec3(coord.x * sinThetaCoord, coord.y * sinThetaCoord, 1.0));\n"
178 // form surface z and project texture onto it.
179 " float indentAmount = 1.0 / (1.0 - (z * uTextureDistortAmount));\n"
180 " vec2 distortedCoord = vCentredCoord * indentAmount;\n"
182 // Convert the rect coordinates in -1 to 1 range back to the original coordinates
183 " 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"
184 " vec4 col = texture2D(sTexture, texCoord);\n"
187 " float lighting = (dot(uDiffuseLight, norm) + uAmbientLight) * uLightMultiplier;\n"
188 " gl_FragColor = vec4(col.rgb * uColor.rgb * lighting, col.a * uColor.a);\n"
192 " vec4 col = texture2D(sTexture, vTexCoord);\n"
193 " float lighting = (dot(uDiffuseLight, vec3(0.0, 0.0, 1.0)) + uAmbientLight) * uLightMultiplier;\n"
194 " gl_FragColor = vec4(col.rgb * uColor.rgb * lighting, col.a * uColor.a);\n"
198 std::string fragmentSourceRectangular;
199 fragmentSourceRectangular = "precision mediump float;\n"
201 "uniform float uLightingIndentationAmount;\n"
202 "uniform float uTextureDistortAmount;\n"
203 "uniform vec3 uDiffuseLight;\n"
204 "uniform float uAmbientLight;\n"
205 "uniform float uLightMultiplier;\n"
206 "uniform float uInsideCircleSizeScale;\n"
207 "uniform float uRecipInsideCircleSizeScale;\n"
208 "uniform float uOutsideCircleDepth;\n"
209 "uniform float uRectangleSizeScale;\n"
210 "uniform vec4 uEffectRegion;\n"
211 "varying vec2 vCentredCoord;\n"
213 "const float PI = 3.1415927;\n"
217 // Apply distortion only if the pixel is within the rect specified
218 "if( (vTexCoord.x > uEffectRegion.x) && (vTexCoord.x < uEffectRegion.z) && (vTexCoord.y > uEffectRegion.y) && (vTexCoord.y < uEffectRegion.w) )\n"
220 // get the rect coords to -1..1 range, i.e. circle centred around the center of the rect
221 " vec2 centredCoord = vCentredCoord;\n"
222 // 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
223 // of the actor, e.g. 0.5 is half way along an axis from centre to actor edge.
224 " vec2 clampedCoord;\n"
225 " if(centredCoord.x > 0.0)\n"
227 " if(centredCoord.x < uRectangleSizeScale)\n"
229 // we are in a rectangular region along this axis, clamp coord to be same as centre pixel
230 " clampedCoord.x = 0.0;\n"
234 // we are outside rectangular region along this axis, so we want curvature.
235 " clampedCoord.x = smoothstep(0.0, 1.0, (centredCoord.x - uRectangleSizeScale) / (1.0 - uRectangleSizeScale));\n"
240 " if(centredCoord.x > -uRectangleSizeScale)\n"
242 // we are in a rectangular region along this axis, clamp coord to be same as centre pixel
243 " clampedCoord.x = 0.0;\n"
247 // we are outside rectangular region along this axis, so we want curvature.
248 " clampedCoord.x = -smoothstep(0.0, 1.0, (centredCoord.x + uRectangleSizeScale) / (uRectangleSizeScale - 1.0));\n"
251 " if(centredCoord.y > 0.0)\n"
253 " if(centredCoord.y < uRectangleSizeScale)\n"
255 // we are in a rectangular region along this axis, clamp coord to be same as centre pixel
256 " clampedCoord.y = 0.0;\n"
260 // we are outside rectangular region along this axis, so we want curvature.
261 " clampedCoord.y = smoothstep(0.0, 1.0, (centredCoord.y - uRectangleSizeScale) / (1.0 - uRectangleSizeScale));\n"
266 " if(centredCoord.y > -uRectangleSizeScale)\n"
268 // we are in a rectangular region along this axis, clamp coord to be same as centre pixel
269 " clampedCoord.y = 0.0;\n"
273 // we are outside rectangular region along this axis, so we want curvature.
274 " clampedCoord.y = -smoothstep(0.0, 1.0, (centredCoord.y + uRectangleSizeScale) / (uRectangleSizeScale - 1.0));\n"
277 // get coords in -PI..PI range, i.e. scale above circle for use by trig functions
278 " vec2 thetaCoord = clampedCoord * PI;\n"
279 // 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)
280 " vec2 cosThetaCoord = (cos(thetaCoord) * 0.5) + 0.5;\n"
281 " float z = cosThetaCoord.x * cosThetaCoord.y;\n"
282 // find a coordinate representing distance from circle centre, such that we split into inside / outside circles that can have different gradients / normals
283 " float realDistFromCentre = length(thetaCoord);\n"
284 " realDistFromCentre = min(PI, realDistFromCentre);\n" // clamp corners of square to vertical normal
285 " float distFromCentre;\n"
286 " if(realDistFromCentre <= PI * uInsideCircleSizeScale)\n"
288 " distFromCentre = realDistFromCentre * uRecipInsideCircleSizeScale * (PI - (uOutsideCircleDepth * PI)) / PI;\n" // inside circle indent, up to outline depth
292 " distFromCentre = mix(PI - (uOutsideCircleDepth * PI), PI, (realDistFromCentre - ( PI * uInsideCircleSizeScale)) / (PI - (PI * uInsideCircleSizeScale)));\n" // outside circle
294 // 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...
295 " float sinThetaCoord = sin(distFromCentre) * uLightingIndentationAmount;\n" // slope, so tangent vec is (1.0, -sin)
296 // ...2D normal vector along distFromCentre vec is (sin, 1.0), convert to components in 3D.
297 " vec3 norm = normalize(vec3(thetaCoord.x * sinThetaCoord, thetaCoord.y * sinThetaCoord, 1.0));\n"
298 // form surface z and project texture onto it.
299 " float indentAmount = 1.0 / (1.0 - (z * uTextureDistortAmount));\n"
300 " vec2 distortedCoord = centredCoord * indentAmount;\n"
301 // Convert the rect coordinates in -1 to 1 range back to the original coordinates
302 " 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"
303 " vec4 col = texture2D(sTexture, texCoord);\n"
305 " float lighting = (dot(uDiffuseLight, norm) + uAmbientLight) * uLightMultiplier;\n"
306 // output col = image * light
307 // use the lighting value for colors only
308 " gl_FragColor = vec4(col.rgb * uColor.rgb * lighting, col.a * uColor.a);\n"
313 " vec4 col = texture2D(sTexture, vTexCoord);\n"
314 " float lighting = (dot(uDiffuseLight, vec3(0.0, 0.0, 1.0)) + uAmbientLight) * uLightMultiplier;\n"
315 " gl_FragColor = vec4(col.rgb * uColor.rgb * lighting, col.a * uColor.a);\n"
320 //////////////////////////////////////
321 // Create shader effect
329 shader = ShaderEffect::New( vertexSource, fragmentSourceRectangular, GeometryType( GEOMETRY_TYPE_IMAGE ), ShaderEffect::GeometryHints( ShaderEffect::HINT_NONE ));
333 shader = ShaderEffect::New( vertexSource, fragmentSourceElliptical, GeometryType( GEOMETRY_TYPE_IMAGE ), ShaderEffect::GeometryHints( ShaderEffect::HINT_NONE ));
338 shader = ShaderEffect::New( vertexSource, fragmentSourceFixed, GeometryType( GEOMETRY_TYPE_IMAGE ), ShaderEffect::GeometryHints( ShaderEffect::HINT_NONE ));
341 SoftButtonEffect handle( shader );
344 //////////////////////////////////////
345 // Register uniform properties
349 // factors that scale the look, defaults
350 handle.SetUniform(SOFT_BUTTON_AMBIENT_LIGHT_AMOUNT_PROPERTY_NAME, SOFT_BUTTON_AMBIENT_LIGHT_AMOUNT_DEFAULT);
351 handle.SetUniform(SOFT_BUTTON_DIFFUSE_LIGHT_PROPERTY_NAME, SOFT_BUTTON_DIFFUSE_LIGHT_DEFAULT);
352 handle.SetUniform(SOFT_BUTTON_LIGHTING_MULTIPLIER_PROPERTY_NAME, SOFT_BUTTON_LIGHTING_MULTIPLIER_DEFAULT);
355 handle.SetUniform(SOFT_BUTTON_LIGHTING_INDENTATION_AMOUNT_PROPERTY_NAME, SOFT_BUTTON_LIGHTING_INDENTATION_AMOUNT_DEFAULT);
356 handle.SetUniform(SOFT_BUTTON_TEXTURE_DISTORTION_AMOUNT_PROPERTY_NAME, SOFT_BUTTON_TEXTURE_DISTORTION_AMOUNT_DEFAULT);
357 handle.SetUniform(SOFT_BUTTON_INSIDE_SHAPE_SIZE_SCALE_PROPERTY_NAME, SOFT_BUTTON_INSIDE_SHAPE_SIZE_SCALE_DEFAULT);
358 handle.SetUniform(SOFT_BUTTON_RECIP_INSIDE_SHAPE_SIZE_SCALE_PROPERTY_NAME, 1.0f / SOFT_BUTTON_INSIDE_SHAPE_SIZE_SCALE_DEFAULT);
359 handle.SetUniform(SOFT_BUTTON_OUTSIDE_SHAPE_DEPTH_PROPERTY_NAME, SOFT_BUTTON_OUTSIDE_SHAPE_DEPTH_DEFAULT);
360 handle.SetUniform(SOFT_BUTTON_EFFECT_PIXEL_AREA_PROPERTY_NAME, SOFT_BUTTON_EFFECT_PIXEL_AREA_DEFAULT);
361 if(RECTANGULAR == type)
363 handle.SetUniform(SOFT_BUTTON_RECTANGLE_SIZE_SCALE_PROPERTY_NAME, SOFT_BUTTON_RECTANGLE_SIZE_SCALE_DEFAULT);
366 // precalc 1.0 / uInsideCircleSizeScale on CPU to save shader insns, using constraint to tie to the normal property
367 Property::Index insideCircleSizeScalePropertyIndex = handle.GetPropertyIndex(SOFT_BUTTON_INSIDE_SHAPE_SIZE_SCALE_PROPERTY_NAME);
368 Property::Index recipInsideCircleSizeScalePropertyIndex = handle.GetPropertyIndex(SOFT_BUTTON_RECIP_INSIDE_SHAPE_SIZE_SCALE_PROPERTY_NAME);
369 Constraint constraint = Constraint::New<float>( recipInsideCircleSizeScalePropertyIndex, LocalSource(insideCircleSizeScalePropertyIndex), ReciprocalConstraint());
370 handle.ApplyConstraint(constraint);
376 const std::string& SoftButtonEffect::GetLightingIndentationAmountPropertyName() const
378 return SOFT_BUTTON_LIGHTING_INDENTATION_AMOUNT_PROPERTY_NAME;
381 const std::string& SoftButtonEffect::GetTextureDistortionAmountPropertyName() const
383 return SOFT_BUTTON_TEXTURE_DISTORTION_AMOUNT_PROPERTY_NAME;
386 const std::string& SoftButtonEffect::GetAmbientLightAmountPropertyName() const
388 return SOFT_BUTTON_AMBIENT_LIGHT_AMOUNT_PROPERTY_NAME;
391 const std::string& SoftButtonEffect::GetDiffuseLightPropertyName() const
393 return SOFT_BUTTON_DIFFUSE_LIGHT_PROPERTY_NAME;
396 const std::string& SoftButtonEffect::GetLightingMultiplierPropertyName() const
398 return SOFT_BUTTON_LIGHTING_MULTIPLIER_PROPERTY_NAME;
401 const std::string& SoftButtonEffect::GetInsideShapeSizeScalePropertyName() const
403 return SOFT_BUTTON_INSIDE_SHAPE_SIZE_SCALE_PROPERTY_NAME;
406 const std::string& SoftButtonEffect::GetOutsideShapeDepthPropertyName() const
408 return SOFT_BUTTON_OUTSIDE_SHAPE_DEPTH_PROPERTY_NAME;
411 const std::string& SoftButtonEffect::GetEffectPixelAreaPropertyName() const
413 return SOFT_BUTTON_EFFECT_PIXEL_AREA_PROPERTY_NAME;
416 const std::string& SoftButtonEffect::GetRectangleSizeScalePropertyName() const
418 return SOFT_BUTTON_RECTANGLE_SIZE_SCALE_PROPERTY_NAME;