2 // Copyright (c) 2014 Samsung Electronics Co., Ltd.
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
8 // http://floralicense.org/license/
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.
17 #include <dali-toolkit/public-api/shader-effects/soft-button-effect.h>
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" );
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;
53 * ReciprocalConstraint
55 * f(current, property) = 1.0 / property
57 struct ReciprocalConstraint
59 ReciprocalConstraint(){}
61 float operator()(const float current, const PropertyInput& property)
63 return 1.0f / property.GetFloat();
68 ////////////////////////////////////////////////////
70 // Soft button shader / actor tweaking parameters
74 SoftButtonEffect::SoftButtonEffect()
78 //Call the Parent copy constructor to add reference to the implementation for this object
79 SoftButtonEffect::SoftButtonEffect(ShaderEffect handle)
84 SoftButtonEffect::~SoftButtonEffect()
88 SoftButtonEffect SoftButtonEffect::New(Type type)
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"
98 "const vec3 norm = vec3(0.0, 0.0, 1.0);\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"
109 std::string fragmentSourceFixed;
110 fragmentSourceFixed = "precision mediump float;\n"
112 "uniform vec3 uDiffuseLight;\n"
113 "uniform float uAmbientLight;\n"
114 "uniform float uLightMultiplier;\n"
115 "varying vec2 vCentredCoord;\n"
117 "const vec3 norm = vec3(0.0, 0.0, 1.0);\n"
121 " vec4 col = texture2D(sTexture, vTexCoord);\n"
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"
129 std::string fragmentSourceElliptical;
130 fragmentSourceElliptical = "precision mediump float;\n"
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"
143 "const float PI = 3.1415927;\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"
150 " vec2 coord = vCentredCoord;\n"
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"
158 " distFromCentre = realDistFromCentre * uRecipInsideCircleSizeScale * (1.0 - uOutsideCircleDepth);\n" // inside circle indent, up to outline depth
162 " distFromCentre = mix(1.0 - uOutsideCircleDepth, 1.0, (realDistFromCentre - ( uInsideCircleSizeScale)) / (1.0 - uInsideCircleSizeScale));\n" // outside circle
165 // get coords in -PI..PI range, i.e. scale the circle for use by trig functions
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"
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"
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"
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"
186 " float lighting = (dot(uDiffuseLight, norm) + uAmbientLight) * uLightMultiplier;\n"
187 " gl_FragColor = vec4(col.rgb * uColor.rgb * lighting, col.a * uColor.a);\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"
197 std::string fragmentSourceRectangular;
198 fragmentSourceRectangular = "precision mediump float;\n"
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"
212 "const float PI = 3.1415927;\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"
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"
226 " if(centredCoord.x < uRectangleSizeScale)\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"
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"
239 " if(centredCoord.x > -uRectangleSizeScale)\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"
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"
250 " if(centredCoord.y > 0.0)\n"
252 " if(centredCoord.y < uRectangleSizeScale)\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"
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"
265 " if(centredCoord.y > -uRectangleSizeScale)\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"
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"
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"
287 " distFromCentre = realDistFromCentre * uRecipInsideCircleSizeScale * (PI - (uOutsideCircleDepth * PI)) / PI;\n" // inside circle indent, up to outline depth
291 " distFromCentre = mix(PI - (uOutsideCircleDepth * PI), PI, (realDistFromCentre - ( PI * uInsideCircleSizeScale)) / (PI - (PI * uInsideCircleSizeScale)));\n" // outside circle
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"
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"
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"
319 //////////////////////////////////////
320 // Create shader effect
328 shader = ShaderEffect::New( vertexSource, fragmentSourceRectangular, GeometryType( GEOMETRY_TYPE_IMAGE ), ShaderEffect::GeometryHints( ShaderEffect::HINT_NONE ));
332 shader = ShaderEffect::New( vertexSource, fragmentSourceElliptical, GeometryType( GEOMETRY_TYPE_IMAGE ), ShaderEffect::GeometryHints( ShaderEffect::HINT_NONE ));
337 shader = ShaderEffect::New( vertexSource, fragmentSourceFixed, GeometryType( GEOMETRY_TYPE_IMAGE ), ShaderEffect::GeometryHints( ShaderEffect::HINT_NONE ));
340 SoftButtonEffect handle( shader );
343 //////////////////////////////////////
344 // Register uniform properties
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);
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)
362 handle.SetUniform(SOFT_BUTTON_RECTANGLE_SIZE_SCALE_PROPERTY_NAME, SOFT_BUTTON_RECTANGLE_SIZE_SCALE_DEFAULT);
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);
375 const std::string& SoftButtonEffect::GetLightingIndentationAmountPropertyName() const
377 return SOFT_BUTTON_LIGHTING_INDENTATION_AMOUNT_PROPERTY_NAME;
380 const std::string& SoftButtonEffect::GetTextureDistortionAmountPropertyName() const
382 return SOFT_BUTTON_TEXTURE_DISTORTION_AMOUNT_PROPERTY_NAME;
385 const std::string& SoftButtonEffect::GetAmbientLightAmountPropertyName() const
387 return SOFT_BUTTON_AMBIENT_LIGHT_AMOUNT_PROPERTY_NAME;
390 const std::string& SoftButtonEffect::GetDiffuseLightPropertyName() const
392 return SOFT_BUTTON_DIFFUSE_LIGHT_PROPERTY_NAME;
395 const std::string& SoftButtonEffect::GetLightingMultiplierPropertyName() const
397 return SOFT_BUTTON_LIGHTING_MULTIPLIER_PROPERTY_NAME;
400 const std::string& SoftButtonEffect::GetInsideShapeSizeScalePropertyName() const
402 return SOFT_BUTTON_INSIDE_SHAPE_SIZE_SCALE_PROPERTY_NAME;
405 const std::string& SoftButtonEffect::GetOutsideShapeDepthPropertyName() const
407 return SOFT_BUTTON_OUTSIDE_SHAPE_DEPTH_PROPERTY_NAME;
410 const std::string& SoftButtonEffect::GetEffectPixelAreaPropertyName() const
412 return SOFT_BUTTON_EFFECT_PIXEL_AREA_PROPERTY_NAME;
415 const std::string& SoftButtonEffect::GetRectangleSizeScalePropertyName() const
417 return SOFT_BUTTON_RECTANGLE_SIZE_SCALE_PROPERTY_NAME;