Merge branch 'tizen' into devel/new_mesh
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / devel-api / shader-effects / displacement-effect.h
1 #ifndef __DALI_TOOLKIT_SHADER_EFFECT_DISPLACEMENT_H__
2 #define __DALI_TOOLKIT_SHADER_EFFECT_DISPLACEMENT_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 <dali/public-api/shader-effects/shader-effect.h>
23
24 namespace Dali
25 {
26
27 namespace Toolkit
28 {
29
30 /**
31  * @brief Creates a new displacement effect
32  *
33  * Two state displacement effect shader that works on a per object basis. By passing a height-normal map as an effect image, the user can create
34  * various styles of buttons on an image actor. The shader requires two height-normal maps in one image, one for each state.
35  *
36  *    The normals and height information for the two states of the button should be strictly specified in this format:
37  *     ______________
38  *    |   State 0    |
39  *    |              |
40  *    |              | --> Unpressed button normals in rgb and height in a
41  *    |     Map      |
42  *    |______________|
43  *    |   State 1    |
44  *    |              |
45  *    |              | --> Pressed button normals in rgb and height in a
46  *    |     Map      |
47  *    |______________|
48  *
49  *    The RGB values should contain the surface normals and the alpha should contian the height map. For a better effect keep the highest point (alpha value) in
50  *    the combined map as 1.0 and the lowest posint as 0.0 and 0.5 for any region which doesn't need displacement.
51  *
52  *    For the supplied Normal map the Y-Axis should be down, Meaning (0,0) is in the top left. As the shader inverts the Y axis for lighting calculation.
53  *
54  *    Limitations: Can be applied to ImageActor only, And doesn't provide support for specular color.
55  *
56  * Usage example:-
57  *
58  * // Create shader used for doing soft button\n
59  * ShaderEffect buttonEffect = CreateDisplacementEffect();
60  * buttonEffect.SetEffectImage(Image::New( FANCY_BUTTON_HEIGHT_MAP_IMAGE_PATH ););
61  *
62  * // set shader to the soft button\n
63  * ImageActor fancyButton = ImageActor::New( ... );\n
64  * fancyButton.SetShaderEffect( buttonEffect );
65  *
66  * // animate a button push, using e.g. AlphaFunction::BOUNCE. With these values the button pushes in and out (animates to and fro between the two states)
67  *
68  *
69  * Animation animation = Animation::New( ... );\n
70  * animation.AnimateTo( Property(buttonEffect, "uState"), 1.0f, AlphaFunction::BOUNCE, ... );\n
71  * animation.Play();\n
72  *
73  * Animatable/Constrainable uniforms:
74  *   "uLightDirection"      - The light direction is used in the lighting calculation. The angle of incidence directly affects the amount of light reflected.
75  *                            Default (0.0f, 0.7070168f, 0.7071068f), i.e angled at the surface from in front and above.
76  *   "uAmbientLightColor"   - The ambient light is used in the lighting calculation. Care must be taken to not saturate the image by setting this value too high,
77  *                            or the indentation will not look correct. Default 0.15.
78  *   "uDiffuseLightColor"   - The diffuse light is used in the lighting calculation. Default is (1.0f, 1.0f, 1.0f).
79  *   "uLightMultiplier"     - The ambient and diffuse lighting is multiplied by this factor. Since a diffuse light at an angle will cause the whole image to darken,
80  *                            this property can be used to scale the image back up closer to the pixel values of the original diffuse texture. Care must be taken
81  *                            to not saturate the image,or the indentation will not look correct. Default 1.0
82  *   "uState"               - The shader can have a maximum of two end states 0 or 1, Animate between these two values to do the transitions
83  *                            between states. Default 0.0
84  *   "uHightScale"          - The height displacement is multiplied by this factor. Tweak this to get the required level of depth. Default 0.1
85  *   "uFixedNormal"         - The Fixed normal will be used for the light calculation. Tweak this to get the required level of light.
86  *                            Only applicable for the FIXED type shader and not for DISPLACED type
87  *
88  * @param type The type of the effect, can be either DISPLACED, or FIXED.
89  * @return A handle to a newly allocated ShaderEffect
90  *
91  */
92
93 typedef enum
94 {
95   DISPLACEMENT_EFFECT_DISPLACED = 0,    /// Image gets displaced
96   DISPLACEMENT_EFFECT_FIXED             /// Image does not displace. Useful for matching lighting between areas that do not displace and those that do, e.g for backgrounds which are visible between buttons.
97 }DisplacementEffectType;
98
99 inline ShaderEffect CreateDisplacementEffect(DisplacementEffectType type)
100 {
101   std::string fragmentSourceFixed;
102   fragmentSourceFixed =  "precision mediump float;\n"
103       "uniform vec3 uLightDirection;\n"
104       "uniform vec3 uAmbientLightColor;\n"
105       "uniform vec3 uDiffuseLightColor;\n"
106       "uniform float uLightMultiplier;\n"
107       "uniform float uState;\n"
108       "uniform float uHightScale;\n"
109       "uniform vec3 uFixedNormal;\n"
110
111       "void main()\n"
112       "{\n"
113       "  vec4 col = texture2D(sTexture, vTexCoord);\n"
114       // calc lighting
115       "  float intensity = dot(uLightDirection, uFixedNormal);"
116       "  vec3 lighting = (intensity * uDiffuseLightColor) + uAmbientLightColor;\n"
117       "  lighting *= uLightMultiplier;\n"
118       // output col = image * light
119       "  gl_FragColor = vec4(col.rgb * lighting * uColor.rgb, col.a * uColor.a);\n"
120       "}\n";
121
122
123
124   std::string fragmentSourceDisplaced(
125       "precision mediump float;\n"
126       "uniform vec3 uLightDirection;\n"
127       "uniform vec3 uAmbientLightColor;\n"
128       "uniform vec3 uDiffuseLightColor;\n"
129       "uniform float uLightMultiplier;\n"
130       "uniform float uState;\n"
131       "uniform float uHightScale;\n"
132       "void main()\n"
133       "{\n"
134       "  highp vec4 displacementMap1 = texture2D(sEffect, vec2(vTexCoord.s, vTexCoord.t/2.0));\n"
135       "  highp vec4 displacementMap2 = texture2D(sEffect, vec2(vTexCoord.s, 0.5+vTexCoord.t/2.0));\n"
136       "  highp vec4 displacementMap = mix(displacementMap1, displacementMap2, uState);\n"
137
138       "  vec3 normalAdjusted = normalize(displacementMap.rgb*2.0-1.0);\n"
139       "  float height = uHightScale * (displacementMap.a*2.0 - 1.0);\n"
140       "  vec2 displacement = vec2(0.0);\n"
141       "  displacement += (vec2(0.5)-vTexCoord.st)*height;\n"
142       "  vec2 newCoord = vTexCoord.st + displacement.xy;\n"
143
144       "  vec4 col = texture2D(sTexture, newCoord);\n"
145       // Y-Axis for the normal map is taken as in Y-Down format, So inverting it for GL
146       "  float intensity = dot(uLightDirection, vec3(1.0,-1.0, 1.0) * normalAdjusted);"
147       "  vec3 lighting = (intensity * uDiffuseLightColor) + uAmbientLightColor;\n"
148       "  lighting *= uLightMultiplier;\n"
149       "  vec3 color = col.rgb * lighting * uColor.rgb;\n"
150       "  gl_FragColor = vec4(color, col.a * uColor.a);\n"
151       "}\n");
152
153   //////////////////////////////////////
154   // Create shader effect
155   //
156   //
157
158   ShaderEffect shaderEffect;
159   switch(type)
160   {
161     case DISPLACEMENT_EFFECT_DISPLACED:
162       shaderEffect = ShaderEffect::New( "", fragmentSourceDisplaced);
163       break;
164
165     case DISPLACEMENT_EFFECT_FIXED:
166     default:
167       shaderEffect = ShaderEffect::New( "", fragmentSourceFixed);
168       break;
169   }
170
171
172   //////////////////////////////////////
173   // Register uniform properties
174   //
175   //
176   // factors that scale the look, defaults
177   shaderEffect.SetUniform("uLightDirection",Vector3(0.0, 0.7070168f, 0.7071068f));
178   shaderEffect.SetUniform("uAmbientLightColor",Vector3(0.15f, 0.15f, 0.15f));
179   shaderEffect.SetUniform("uDiffuseLightColor",Vector3(1.0f, 1.0f, 1.0f));
180   shaderEffect.SetUniform("uLightMultiplier",1.0f);
181   shaderEffect.SetUniform("uState",0.0f);
182   shaderEffect.SetUniform("uHightScale",0.1f);
183
184   if(type == DISPLACEMENT_EFFECT_FIXED)
185   {
186     shaderEffect.SetUniform("uFixedNormal",Vector3(0.0f, 0.0f, 1.0f) );
187   }
188
189   return shaderEffect;
190 }
191
192 }
193
194 }
195
196 #endif //#ifndef __DALI_TOOLKIT_SHADER_EFFECT_DISPLACEMENT_H__