Added UNDERLINE_HEIGHT property to TextLabel to override adaptor metrics and rounded...
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / public-api / shader-effects / motion-stretch-effect.cpp
1 /*
2  * Copyright (c) 2014 Samsung Electronics Co., Ltd.
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
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
18 // CLASS HEADER
19 #include <dali-toolkit/public-api/shader-effects/motion-stretch-effect.h>
20
21 // EXTERNAL INCLUDES
22 #include <dali/public-api/animation/active-constraint.h>
23 #include <dali/public-api/animation/constraint.h>
24 #include <dali/public-api/animation/constraints.h>
25
26 namespace Dali
27 {
28
29 namespace Toolkit
30 {
31
32 namespace
33 {
34
35 struct MatrixFromPropertiesConstraint
36 {
37   MatrixFromPropertiesConstraint()
38   {
39   }
40
41   Matrix operator()( const Matrix& current,
42                      const PropertyInput& propertyPosition,
43                      const PropertyInput& propertyOrientation,
44                      const PropertyInput& propertyScale )
45   {
46     Matrix mat4( false );
47     mat4.SetTransformComponents( propertyScale.GetVector3(),
48                                  propertyOrientation.GetQuaternion(),
49                                  propertyPosition.GetVector3() );
50
51     return mat4;
52   }
53 };
54
55 const std::string MOTION_STRETCH_GEOMETRY_STRETCH_SCALING_FACTOR_PROPERTY_NAME( "uGeometryStretchFactor" );
56 const std::string MOTION_STRETCH_SPEED_SCALING_FACTOR_PROPERTY_NAME( "uSpeedScalingFactor" );
57 const std::string MOTION_STRETCH_OBJECT_FADE_START_PROPERTY_NAME( "uObjectFadeStart" );
58 const std::string MOTION_STRETCH_OBJECT_FADE_END_PROPERTY_NAME( "uObjectFadeEnd" );
59 const std::string MOTION_STRETCH_ALPHA_SCALE_PROPERTY_NAME( "uAlphaScale" );
60 const std::string MOTION_STRETCH_MODELVIEW_LASTFRAME( "uModelLastFrame" );  ///< Matrix
61
62 ////////////////////////////////////////////////////
63 //
64 // Motion stretch shader / actor tweaking parameters
65 //
66
67 // half width and half height respectively of actor, corresponding to values in vertex attribute stream
68 // Note that these values work for normal image actor (verts +/- 0.5) but a grid or a nine square seemsi
69 // to have verts in pixel space (e.g. 256,256). Need to fix this somehow,
70 // either in Dali or by passing uniforms which we can use to 'normalise' the verts in the vertex shader
71 const Vector2 MOTION_STRETCH_ACTOR_VERTEX( 0.5f, 0.5f );
72
73 const float MOTION_STRETCH_GEOM_STRETCH_SCALING_FACTOR = 0.5f; // scaling factor for how much to stretch actor geom as it moves
74 const float MOTION_STRETCH_SPEED_SCALING_FACTOR = 0.5f;        // scales the speed, producing a number affecting how much the actor stretches & fades at the edges
75
76 const Vector2 MOTION_STRETCH_OBJECT_FADE_END( MOTION_STRETCH_ACTOR_VERTEX );             // displacement from center at which actor fully fades to zero alpha
77 const Vector2 MOTION_STRETCH_OBJECT_FADE_START( MOTION_STRETCH_OBJECT_FADE_END * 0.5f ); // displacement from center at which actor start to fade from full alpha
78
79 const float MOTION_STRETCH_ALPHA_SCALE = 0.75f; // global scaler applied to actor alpha as it is stretched + moving
80
81 } // namespace
82
83
84 MotionStretchEffect::MotionStretchEffect()
85 {
86 }
87
88 // Call the Parent copy constructor to add reference to the implementation for this object
89 MotionStretchEffect::MotionStretchEffect( ShaderEffect handle )
90 :ShaderEffect( handle )
91 {
92 }
93
94 MotionStretchEffect::~MotionStretchEffect()
95 {
96 }
97
98 MotionStretchEffect MotionStretchEffect::Apply( RenderableActor renderable )
99 {
100   MotionStretchEffect newEffect = New();
101   renderable.SetShaderEffect( newEffect );
102
103   Dali::Property::Index uModelProperty = newEffect.GetPropertyIndex( MOTION_STRETCH_MODELVIEW_LASTFRAME );
104
105   Constraint constraint = Constraint::New<Matrix>( uModelProperty,
106                                                    Source( renderable, Actor::Property::WORLD_MATRIX ),
107                                                    EqualToConstraint() );
108
109   // and set up constraint.
110   newEffect.ApplyConstraint(constraint);
111   return newEffect;
112 }
113
114 MotionStretchEffect MotionStretchEffect::New()
115 {
116   // Dali vertexSource prefix for reference:
117   // precision highp float;
118   // attribute vec3  aPosition;
119   // attribute vec2  aTexCoord;
120   // uniform   mat4  uMvpMatrix;
121   // uniform   mat4  uModelView;
122   // uniform   mat3  uNormalMatrix;
123   // uniform   mat4  uProjection;
124   // uniform   vec4  uColor;
125   // varying   vec2  vTexCoord;
126   std::string vertexSource;
127   vertexSource =
128     "precision mediump float;\n"
129     "uniform mat4  uModelLastFrame;\n"
130     "uniform float uTimeDelta;\n"
131
132     "uniform float uGeometryStretchFactor;\n"
133     "uniform float uSpeedScalingFactor;\n"
134
135     // outputs
136     "varying vec2 vModelSpaceCenterToPos;\n"
137     "varying vec2 vScreenSpaceVelocityVector;\n"
138     "varying float vSpeed;\n"
139
140     "void main()\n"
141     "{\n"
142     // get view space position of vertex this frame and last frame
143     " vec4 vertex = vec4(aPosition, 1.0);\n"
144     " vec4 viewSpaceVertex = uModelView * vertex;\n"
145     " vec4 viewSpaceVertexLastFrame = uViewMatrix * uModelLastFrame * vertex;\n"
146
147     // work out vertex's last movement in view space
148     " vec3 viewSpacePosDelta = viewSpaceVertex.xyz - viewSpaceVertexLastFrame.xyz;\n"
149     " float reciprocalTimeDelta = 1.0 / ((uTimeDelta > 0.0) ? uTimeDelta : 0.01);\n"
150
151     // get clip space position of vertex this frame and last frame
152     " vec4 clipSpaceVertex = uMvpMatrix * vertex;\n"
153     " vec4 clipSpaceVertexLastFrame = uProjection * viewSpaceVertexLastFrame;\n"
154
155     // decide how much this vertex is 'trailing', i.e. at the back of the object relative to its direction of motion. We do this
156     // by assuming the objects model space origin is at its center and taking the dot product of the vector from center to vertex with the motion direction
157     " float t = 0.0;\n"
158     " float posDeltaLength = length(viewSpacePosDelta);\n"
159     " if(posDeltaLength > 0.001)\n" // avoid div by 0 if object has barely moved
160     " {\n"
161     "   vec4 viewSpaceCenterToPos = uModelView * vec4(aPosition, 0.0);\n"
162     "   float centerToVertexDist = length(viewSpaceCenterToPos);\n"
163     "   if(centerToVertexDist > 0.001)\n" // avoid div by 0 if object has vertex at model space origin
164     "   {\n"
165     "     vec3 viewSpacePosDeltaNormalised = viewSpacePosDelta / posDeltaLength;\n"
166     "     vec3 viewSpaceCenterToPosNormalised = viewSpaceCenterToPos.xyz / centerToVertexDist;\n"
167     "     t = (dot(viewSpacePosDeltaNormalised, viewSpaceCenterToPosNormalised) * 0.5 ) + 0.5;\n" // scale and bias from [-1..1] to [0..1]
168     "   }\n"
169     " }\n"
170     // output vertex position lerped with its last position, based on how much it is trailing,
171     // this stretches the geom back along where it has just been, giving a warping effect
172     // We raise t to a power in order that non-trailing vertices are effected much more than trailing ones
173     // Note: we must take account of time delta to convert position delta into a velocity, so changes are smooth (take into account frame time correctly)
174     " gl_Position = mix(clipSpaceVertexLastFrame, clipSpaceVertex, t * t * t * uGeometryStretchFactor * reciprocalTimeDelta);\n"
175
176     // work out vertex's last movement in normalised device coordinates [-1..1] space, i.e. perspective divide
177     " vec2 ndcVertex = clipSpaceVertex.xy / clipSpaceVertex.w;\n"
178     " vec2 ndcVertexLastFrame = clipSpaceVertexLastFrame.xy / clipSpaceVertexLastFrame.w;\n"
179     // scale and bias so that a value of 1.0 corresponds to screen size (NDC is [-1..1] = 2)
180     " vScreenSpaceVelocityVector = ((ndcVertex - ndcVertexLastFrame) * 0.5 * reciprocalTimeDelta);\n"
181     " vScreenSpaceVelocityVector.y = -vScreenSpaceVelocityVector.y;\n" // TODO negated due to y being inverted in our coordinate system?
182     // calculate a scaling factor proportional to velocity, which we can use to tweak how things look
183     " vSpeed = length(vScreenSpaceVelocityVector) * uSpeedScalingFactor;\n"
184     " vSpeed = clamp(vSpeed, 0.0, 1.0);\n"
185
186     // provide fragment shader with vector from center of object to pixel (assumes the objects model space origin is at its center and verts have same z)
187     " vModelSpaceCenterToPos = aPosition.xy;\n"
188
189     " vTexCoord = aTexCoord;\n"
190     "}\n";
191
192
193   // Dali fragmentSource prefix for reference:
194   // precision highp     float;
195   // uniform   sampler2D sTexture;
196   // uniform   sampler2D sEffect;
197   // uniform   vec4      uColor;
198   // varying   vec2      vTexCoord;
199   std::string fragmentSource;
200   fragmentSource =
201     "precision mediump float;\n"
202
203     "uniform vec2 uObjectFadeStart;\n"
204     "uniform vec2 uObjectFadeEnd;\n"
205     "uniform float uAlphaScale;\n"
206
207     // inputs
208     "varying vec2 vModelSpaceCenterToPos;\n"
209     "varying vec2 vScreenSpaceVelocityVector;\n"
210     "varying float vSpeed;\n"
211
212     "void main()\n"
213     "{\n"
214     // calculate an alpha value that will fade the object towards its extremities, we need this to avoid an unsightly hard edge between color values of
215     // the stretched object and the background. Use smoothstep also to hide any hard edges (discontinuities) in rate of change of this alpha gradient
216     " vec2 centerToPixel = abs( vModelSpaceCenterToPos );\n"
217     " vec2 fadeToEdges = smoothstep(0.0, 1.0, 1.0 - ((centerToPixel - uObjectFadeStart) / (uObjectFadeEnd - uObjectFadeStart)));\n"
218     " float fadeToEdgesScale = fadeToEdges.x * fadeToEdges.y * uAlphaScale;\n" // apply global scaler
219     " fadeToEdgesScale = mix(1.0, fadeToEdgesScale, vSpeed);\n" // fade proportional to speed, so opaque when at rest
220
221     // standard actor texel
222     " vec4 colActor = texture2D(sTexture, vTexCoord);\n"
223     " gl_FragColor = colActor;\n"
224     " gl_FragColor.a *= fadeToEdgesScale;\n" // fade actor to its edges based on speed of motion
225     " gl_FragColor *= uColor;\n"
226     "}";
227
228   // NOTE: we must turn on alpha blending for the actor (HINT_BLENDING)
229   ShaderEffect shader = ShaderEffect::New(
230     vertexSource, fragmentSource, GeometryType( GEOMETRY_TYPE_IMAGE ),
231     ShaderEffect::GeometryHints( ShaderEffect::HINT_BLENDING | ShaderEffect::HINT_GRID ) );
232
233
234
235   MotionStretchEffect handle( shader );
236
237
238   //////////////////////////////////////
239   // Register uniform properties
240   //
241   //
242
243   // factors that scale the look, defaults
244   handle.SetUniform( MOTION_STRETCH_GEOMETRY_STRETCH_SCALING_FACTOR_PROPERTY_NAME, MOTION_STRETCH_GEOM_STRETCH_SCALING_FACTOR );
245   handle.SetUniform( MOTION_STRETCH_SPEED_SCALING_FACTOR_PROPERTY_NAME, MOTION_STRETCH_SPEED_SCALING_FACTOR );
246   handle.SetUniform( MOTION_STRETCH_OBJECT_FADE_START_PROPERTY_NAME, MOTION_STRETCH_OBJECT_FADE_START );
247   handle.SetUniform( MOTION_STRETCH_OBJECT_FADE_END_PROPERTY_NAME, MOTION_STRETCH_OBJECT_FADE_END );
248   handle.SetUniform( MOTION_STRETCH_ALPHA_SCALE_PROPERTY_NAME, MOTION_STRETCH_ALPHA_SCALE );
249   handle.SetUniform( MOTION_STRETCH_MODELVIEW_LASTFRAME, Matrix::IDENTITY );
250
251   return handle;
252 }
253
254 void MotionStretchEffect::SetGeometryStretchFactor( float scalingFactor )
255 {
256   SetUniform( MOTION_STRETCH_GEOMETRY_STRETCH_SCALING_FACTOR_PROPERTY_NAME, scalingFactor );
257 }
258
259 void MotionStretchEffect::SetSpeedScalingFactor( float scalingFactor )
260 {
261   SetUniform( MOTION_STRETCH_SPEED_SCALING_FACTOR_PROPERTY_NAME, scalingFactor );
262 }
263
264 void MotionStretchEffect::SetObjectFadeStart( Vector2 displacement )
265 {
266   SetUniform( MOTION_STRETCH_OBJECT_FADE_START_PROPERTY_NAME, displacement );
267 }
268
269 void MotionStretchEffect::SetObjectFadeEnd( Vector2 displacement )
270 {
271   SetUniform( MOTION_STRETCH_OBJECT_FADE_END_PROPERTY_NAME, displacement );
272 }
273
274 void MotionStretchEffect::SetAlphaScale( float alphaScale )
275 {
276   SetUniform( MOTION_STRETCH_ALPHA_SCALE_PROPERTY_NAME, alphaScale );
277 }
278
279 const std::string& MotionStretchEffect::GetGeometryStretchFactorPropertyName() const
280 {
281   return MOTION_STRETCH_GEOMETRY_STRETCH_SCALING_FACTOR_PROPERTY_NAME;
282 }
283
284 const std::string& MotionStretchEffect::GetSpeedScalingFactorPropertyName() const
285 {
286   return MOTION_STRETCH_SPEED_SCALING_FACTOR_PROPERTY_NAME;
287 }
288
289 const std::string& MotionStretchEffect::GetObjectFadeStartPropertyName() const
290 {
291   return MOTION_STRETCH_OBJECT_FADE_START_PROPERTY_NAME;
292 }
293
294 const std::string& MotionStretchEffect::GetObjectFadeEndPropertyName() const
295 {
296   return MOTION_STRETCH_OBJECT_FADE_END_PROPERTY_NAME;
297 }
298
299 const std::string& MotionStretchEffect::GetAlphaScalePropertyName() const
300 {
301   return MOTION_STRETCH_ALPHA_SCALE_PROPERTY_NAME;
302 }
303
304 }
305
306 }