[dali_2.3.19] Merge branch 'devel/master'
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / graphics / shaders / image-visual-shader.frag
1 INPUT mediump vec2 vTexCoord;
2 #if defined(IS_REQUIRED_DEBUG_VISUAL_SHADER) || defined(IS_REQUIRED_ROUNDED_CORNER) || defined(IS_REQUIRED_BORDERLINE)
3 INPUT highp vec2 vPosition;
4 INPUT highp vec2 vRectSize;
5 INPUT highp vec2 vOptRectSize;
6 INPUT highp float vAliasMargin;
7 #ifdef IS_REQUIRED_ROUNDED_CORNER
8 INPUT highp vec4 vCornerRadius;
9 #endif
10 #endif
11 #ifdef IS_REQUIRED_DEBUG_VISUAL_SHADER
12 #define DEBUG_EXTRA_VARYINGS
13 DEBUG_EXTRA_VARYINGS
14 #endif
15
16 uniform sampler2D sTexture;
17 #if defined(IS_REQUIRED_YUV_TO_RGB) || defined(IS_REQUIRED_UNIFIED_YUV_AND_RGB)
18 uniform sampler2D sTextureU;
19 uniform sampler2D sTextureV;
20 #endif
21
22 #ifdef IS_REQUIRED_ALPHA_MASKING
23 uniform sampler2D sMaskTexture;
24 uniform lowp float uYFlipMaskTexture;
25 INPUT mediump vec2 vMaskTexCoord;
26 #endif
27
28 #ifdef ATLAS_DEFAULT_WARP
29 uniform mediump vec4 uAtlasRect;
30 #elif defined(ATLAS_CUSTOM_WARP)
31 // WrapMode -- 0: CLAMP; 1: REPEAT; 2: REFLECT;
32 uniform lowp vec2 wrapMode;
33 #endif
34
35
36 #if defined(IS_REQUIRED_DEBUG_VISUAL_SHADER)
37 uniform highp vec3 uScale;
38 #endif
39
40 uniform lowp vec4 uColor;
41 uniform lowp vec3 mixColor;
42 uniform lowp float preMultipliedAlpha;
43 #ifdef IS_REQUIRED_BORDERLINE
44 uniform highp float borderlineWidth;
45 uniform highp float borderlineOffset;
46 uniform lowp vec4 borderlineColor;
47 uniform lowp vec4 uActorColor;
48 #endif
49
50 #ifdef ATLAS_CUSTOM_WARP
51 mediump float wrapCoordinate( mediump vec2 range, mediump float coordinate, lowp float wrap )
52 {
53   mediump float coord;
54   if( wrap > 1.5 ) /* REFLECT */
55     coord = 1.0 - abs(fract(coordinate*0.5)*2.0 - 1.0);
56   else /* warp is 0 or 1 */
57     coord = mix(coordinate, fract(coordinate), wrap);
58   return clamp(mix(range.x, range.y, coord), range.x, range.y);
59 }
60 #endif
61
62 #if defined(IS_REQUIRED_DEBUG_VISUAL_SHADER) || defined(IS_REQUIRED_ROUNDED_CORNER) || defined(IS_REQUIRED_BORDERLINE)
63 // Global values both rounded corner and borderline use
64
65 // radius of rounded corner on this quadrant
66 highp float gRadius = 0.0;
67
68 // fragment coordinate. NOTE : vec2(0.0, 0.0) is vRectSize, the corner of visual
69 highp vec2 gFragmentPosition = vec2(0.0, 0.0);
70 // center coordinate of rounded corner circle. vec2(gCenterPosition, gCenterPosition).
71 highp float gCenterPosition = 0.0;
72 // relative coordinate of gFragmentPosition from gCenterPosition.
73 highp vec2 gDiff = vec2(0.0, 0.0);
74 // potential value what our algorithm use.
75 highp float gPotential = 0.0;
76
77 // threshold of potential
78 highp float gPotentialRange = 0.0;
79 highp float gMaxOutlinePotential = 0.0;
80 highp float gMinOutlinePotential = 0.0;
81 highp float gMaxInlinePotential = 0.0;
82 highp float gMinInlinePotential = 0.0;
83
84 void calculateCornerRadius()
85 {
86 #ifdef IS_REQUIRED_ROUNDED_CORNER
87   gRadius =
88   mix(
89     mix(vCornerRadius.x, vCornerRadius.y, sign(vPosition.x) * 0.5 + 0.5),
90     mix(vCornerRadius.w, vCornerRadius.z, sign(vPosition.x) * 0.5 + 0.5),
91     sign(vPosition.y) * 0.5 + 0.5
92   );
93 #endif
94 }
95
96 void calculatePosition()
97 {
98   gFragmentPosition = abs(vPosition) - vRectSize;
99   gCenterPosition = -gRadius;
100 #ifdef IS_REQUIRED_BORDERLINE
101   gCenterPosition += borderlineWidth * (clamp(borderlineOffset, -1.0, 1.0) + 1.0) * 0.5;
102 #endif
103   gDiff = gFragmentPosition - gCenterPosition;
104 }
105
106 void calculatePotential()
107 {
108   gPotential = length(max(gDiff, 0.0)) + min(0.0, max(gDiff.x, gDiff.y));
109 }
110
111 void setupMinMaxPotential()
112 {
113   gPotentialRange = vAliasMargin;
114
115   gMaxOutlinePotential = gRadius + gPotentialRange;
116   gMinOutlinePotential = gRadius - gPotentialRange;
117
118 #ifdef IS_REQUIRED_BORDERLINE
119   gMaxInlinePotential = gMaxOutlinePotential - borderlineWidth;
120   gMinInlinePotential = gMinOutlinePotential - borderlineWidth;
121 #else
122   gMaxInlinePotential = gMaxOutlinePotential;
123   gMinInlinePotential = gMinOutlinePotential;
124 #endif
125
126   // reduce defect near edge of rounded corner.
127   gMaxOutlinePotential += clamp(-min(gDiff.x, gDiff.y) / max(1.0, gRadius), 0.0, 1.0);
128   gMinOutlinePotential += clamp(-min(gDiff.x, gDiff.y) / max(1.0, gRadius), 0.0, 1.0);
129 }
130
131 void PreprocessPotential()
132 {
133   calculateCornerRadius();
134   calculatePosition();
135   calculatePotential();
136
137   setupMinMaxPotential();
138 }
139 #endif
140
141 #ifdef IS_REQUIRED_BORDERLINE
142 lowp vec4 convertBorderlineColor(lowp vec4 textureColor)
143 {
144   highp float potential = gPotential;
145
146   // default opacity of borderline is 0.0
147   mediump float borderlineOpacity = 0.0;
148
149   // calculate borderline opacity by potential
150   if(potential > gMinInlinePotential)
151   {
152     // potential is inside borderline range.
153     borderlineOpacity = smoothstep(gMinInlinePotential, gMaxInlinePotential, potential);
154
155     // Muliply borderlineWidth to resolve very thin borderline
156     borderlineOpacity *= min(1.0, borderlineWidth / gPotentialRange);
157   }
158
159   lowp vec3  borderlineColorRGB   = borderlineColor.rgb * uActorColor.rgb;
160   lowp float borderlineColorAlpha = borderlineColor.a * uActorColor.a;
161   borderlineColorRGB *= mix(1.0, borderlineColorAlpha, preMultipliedAlpha);
162
163   // Calculate inside of borderline when alpha is between (0.0  1.0). So we need to apply texture color.
164   // If borderlineOpacity is exactly 0.0, we always use whole texture color. In this case, we don't need to run below code.
165   // But if borderlineOpacity > 0.0 and borderlineColor.a == 0.0, we need to apply tCornerRadius.
166   if(borderlineOpacity > 0.0 && borderlineColor.a * borderlineOpacity < 1.0)
167   {
168     highp float tCornerRadius = -gCenterPosition + gPotentialRange;
169     highp float MaxTexturelinePotential = tCornerRadius + gPotentialRange;
170     highp float MinTexturelinePotential = tCornerRadius - gPotentialRange;
171     if(potential > MaxTexturelinePotential)
172     {
173       // potential is out of texture range.
174       textureColor = vec4(0.0);
175     }
176     else
177     {
178       // potential is in texture range.
179       lowp float textureAlphaScale = mix(1.0, 0.0, smoothstep(MinTexturelinePotential, MaxTexturelinePotential, potential));
180       textureColor.a *= textureAlphaScale;
181       textureColor.rgb *= mix(textureColor.a, textureAlphaScale, preMultipliedAlpha);
182     }
183
184     borderlineColorAlpha *= borderlineOpacity;
185     borderlineColorRGB *= mix(borderlineColorAlpha, borderlineOpacity, preMultipliedAlpha);
186     // We use pre-multiplied color to reduce operations.
187     // In here, textureColor and borderlineColorRGB is pre-multiplied color now.
188
189     // Manual blend operation with premultiplied colors.
190     // Final alpha = borderlineColorAlpha + (1.0 - borderlineColorAlpha) * textureColor.a.
191     // (Final rgb * alpha) =  borderlineColorRGB + (1.0 - borderlineColorAlpha) * textureColor.rgb
192     // If preMultipliedAlpha == 1.0, just return vec4(rgb*alpha, alpha)
193     // Else, return vec4((rgb*alpha) / alpha, alpha)
194
195     lowp float finalAlpha = mix(textureColor.a, 1.0, borderlineColorAlpha);
196     lowp vec3  finalMultipliedRGB = borderlineColorRGB + (1.0 - borderlineColorAlpha) * textureColor.rgb;
197     // TODO : Need to find some way without division
198     return vec4(finalMultipliedRGB * mix(1.0 / finalAlpha, 1.0, preMultipliedAlpha), finalAlpha);
199   }
200   return mix(textureColor, vec4(borderlineColorRGB, borderlineColorAlpha), borderlineOpacity);
201 }
202 #endif
203
204 #ifdef IS_REQUIRED_ROUNDED_CORNER
205 mediump float calculateCornerOpacity()
206 {
207   highp float potential = gPotential;
208
209   // default opacity is 1.0
210   mediump float opacity = 1.0;
211
212   // calculate borderline opacity by potential
213   if(potential > gMaxOutlinePotential)
214   {
215     // potential is out of borderline range. just discard here
216     discard;
217   }
218   else if(potential > gMinOutlinePotential)
219   {
220     opacity = 1.0 - smoothstep(gMinOutlinePotential, gMaxOutlinePotential, potential);
221   }
222   return opacity;
223 }
224 #endif
225
226 #if defined(IS_REQUIRED_YUV_TO_RGB) || defined(IS_REQUIRED_UNIFIED_YUV_AND_RGB)
227 lowp vec4 ConvertYuvToRgba(mediump vec2 texCoord)
228 {
229 #ifdef IS_REQUIRED_UNIFIED_YUV_AND_RGB
230   // Special case when shader use YUV but actual textures are not YUV format.
231   // In this case, just resturn sTexture.
232   if(textureSize(sTextureU, 0) != textureSize(sTextureV, 0))
233   {
234     return texture(sTexture, texCoord);
235   }
236 #endif
237
238   lowp float y = texture(sTexture, texCoord).r;
239   lowp float u = texture(sTextureU, texCoord).r - 0.5;
240   lowp float v = texture(sTextureV, texCoord).r - 0.5;
241   lowp vec4 rgba;
242   rgba.r = y + (1.403 * v);
243   rgba.g = y - (0.344 * u) - (0.714 * v);
244   rgba.b = y + (1.770 * u);
245   rgba.a = 1.0;
246   return rgba;
247 }
248 #endif
249
250 #ifdef IS_REQUIRED_DEBUG_VISUAL_SHADER
251
252 // Predefined values whether some macro defined or not.
253 // Since we make debug codes replace by macro,
254 // sharp if keyword cannot be used.
255 // Instead, let we use bool values so we can use define checked in script
256 #ifdef IS_REQUIRED_ROUNDED_CORNER
257 const bool IS_REQUIRED_ROUNDED_CORNER_BOOL = true;
258 #else
259 const bool IS_REQUIRED_ROUNDED_CORNER_BOOL = false;
260 #endif
261 #ifdef IS_REQUIRED_BORDERLINE
262 const bool IS_REQUIRED_BORDERLINE_BOOL = true;
263 #else
264 const bool IS_REQUIRED_BORDERLINE_BOOL = false;
265 #endif
266 #ifdef IS_REQUIRED_YUV_TO_RGB
267 const bool IS_REQUIRED_YUV_TO_RGB_BOOL = true;
268 #else
269 const bool IS_REQUIRED_YUV_TO_RGB_BOOL = false;
270 #endif
271 #ifdef IS_REQUIRED_UNIFIED_YUV_AND_RGB
272 const bool IS_REQUIRED_UNIFIED_YUV_AND_RGB_BOOL = true;
273 #else
274 const bool IS_REQUIRED_UNIFIED_YUV_AND_RGB_BOOL = false;
275 #endif
276 #ifdef IS_REQUIRED_ALPHA_MASKING
277 const bool IS_REQUIRED_ALPHA_MASKING_BOOL = true;
278 #else
279 const bool IS_REQUIRED_ALPHA_MASKING_BOOL = false;
280 #endif
281 #ifdef ATLAS_DEFAULT_WARP
282 const bool ATLAS_DEFAULT_WARP_BOOL = true;
283 #else
284 const bool ATLAS_DEFAULT_WARP_BOOL = false;
285 #endif
286 #ifdef ATLAS_CUSTOM_WARP
287 const bool ATLAS_CUSTOM_WARP_BOOL = true;
288 #else
289 const bool ATLAS_CUSTOM_WARP_BOOL = false;
290 #endif
291
292 // These lines in the shader may be replaced with actual definitions by the debug-image-visual-shader-script.json.
293 // DEBUG_TRIGGER_CODE return bool type, and DEBUG_RATIO_CODE return float value which will be clamped between 0.0 and 1.0
294 // If DEBUG_TRIGGER_CODE return true, it mean we will change final color's channel value.
295 // If ratio is 0.0, debug color rate become MINIMUM_DEBUG_COLOR_RATE, and 1.0 than MAXIMUM_DEBUG_COLOR_RATE.
296 #define MINIMUM_DEBUG_COLOR_RATE
297 #define MAXIMUM_DEBUG_COLOR_RATE
298 #define DEBUG_TRIGGER_RED_CODE
299 #define DEBUG_TRIGGER_GREEN_CODE
300 #define DEBUG_TRIGGER_BLUE_CODE
301 #define DEBUG_RATIO_RED_CODE
302 #define DEBUG_RATIO_GREEN_CODE
303 #define DEBUG_RATIO_BLUE_CODE
304 #define DEBUG_EXTRA_UNIFORMS
305
306 DEBUG_EXTRA_UNIFORMS
307
308 const mediump float gMinDebugColorRate = MINIMUM_DEBUG_COLOR_RATE;
309 const mediump float gMaxDebugColorRate = MAXIMUM_DEBUG_COLOR_RATE;
310
311 bool DebugTriggerRed(mediump vec4 originColor)
312 {
313   DEBUG_TRIGGER_RED_CODE
314 }
315
316 bool DebugTriggerGreen(mediump vec4 originColor)
317 {
318   DEBUG_TRIGGER_GREEN_CODE
319 }
320
321 bool DebugTriggerBlue(mediump vec4 originColor)
322 {
323   DEBUG_TRIGGER_BLUE_CODE
324 }
325
326 mediump float DebugRatioRed(mediump vec4 originColor)
327 {
328   DEBUG_RATIO_RED_CODE
329 }
330
331 mediump float DebugRatioGreen(mediump vec4 originColor)
332 {
333   DEBUG_RATIO_GREEN_CODE
334 }
335
336 mediump float DebugRatioBlue(mediump vec4 originColor)
337 {
338   DEBUG_RATIO_BLUE_CODE
339 }
340
341 mediump vec3 ApplyDebugMixColor(mediump vec4 originColor)
342 {
343   mediump float debugColorRateRed = 0.0;
344   mediump float debugColorRateGreen = 0.0;
345   mediump float debugColorRateBlue = 0.0;
346
347   if(DebugTriggerRed(originColor))
348   {
349     debugColorRateRed = mix(gMinDebugColorRate, gMaxDebugColorRate, smoothstep(0.0, 1.0, DebugRatioRed(originColor)));
350   }
351   if(DebugTriggerGreen(originColor))
352   {
353     debugColorRateGreen = mix(gMinDebugColorRate, gMaxDebugColorRate, smoothstep(0.0, 1.0, DebugRatioGreen(originColor)));
354   }
355   if(DebugTriggerBlue(originColor))
356   {
357     debugColorRateBlue = mix(gMinDebugColorRate, gMaxDebugColorRate, smoothstep(0.0, 1.0, DebugRatioBlue(originColor)));
358   }
359
360   mediump float colorRate = max(debugColorRateRed, max(debugColorRateGreen, debugColorRateBlue));
361   mediump vec3 debugColor = vec3(debugColorRateRed, debugColorRateGreen, debugColorRateBlue);
362
363   debugColor *= mix(1.0, originColor.a, preMultipliedAlpha);
364
365   return originColor.rgb * (1.0 - colorRate) + debugColor;
366 }
367 #endif
368
369 void main()
370 {
371 #ifdef ATLAS_DEFAULT_WARP
372   mediump vec2 texCoord = clamp( mix( uAtlasRect.xy, uAtlasRect.zw, vTexCoord ), uAtlasRect.xy, uAtlasRect.zw );
373 #elif defined(ATLAS_CUSTOM_WARP)
374   mediump vec2 texCoord = vec2( wrapCoordinate( uAtlasRect.xz, vTexCoord.x, wrapMode.x ),
375                                 wrapCoordinate( uAtlasRect.yw, vTexCoord.y, wrapMode.y ) );
376 #else
377   mediump vec2 texCoord = vTexCoord;
378 #endif
379
380 #if defined(IS_REQUIRED_YUV_TO_RGB) || defined(IS_REQUIRED_UNIFIED_YUV_AND_RGB)
381   lowp vec4 textureColor = ConvertYuvToRgba(texCoord) * vec4( mixColor, 1.0 ) * uColor;
382 #else
383   lowp vec4 textureColor = TEXTURE( sTexture, texCoord ) * vec4( mixColor, 1.0 ) * uColor;
384 #endif
385
386 #ifdef IS_REQUIRED_ALPHA_MASKING
387   mediump vec2 maskTexCoord = vMaskTexCoord;
388   maskTexCoord.y = mix(maskTexCoord.y, 1.0-maskTexCoord.y, uYFlipMaskTexture);
389   mediump float maskAlpha = TEXTURE(sMaskTexture, maskTexCoord).a;
390   textureColor.a *= maskAlpha;
391   textureColor.rgb *= mix(1.0, maskAlpha, preMultipliedAlpha);
392 #endif
393
394 #if defined(IS_REQUIRED_DEBUG_VISUAL_SHADER) || defined(IS_REQUIRED_ROUNDED_CORNER) || defined(IS_REQUIRED_BORDERLINE)
395 #ifndef IS_REQUIRED_DEBUG_VISUAL_SHADER
396   // skip most potential calculate for performance
397   if(abs(vPosition.x) < vOptRectSize.x && abs(vPosition.y) < vOptRectSize.y)
398   {
399     OUT_COLOR = textureColor;
400   }
401   else
402 #endif
403   {
404     PreprocessPotential();
405 #endif
406
407 #ifdef IS_REQUIRED_BORDERLINE
408     textureColor = convertBorderlineColor(textureColor);
409 #endif
410     OUT_COLOR = textureColor;
411
412 #ifdef IS_REQUIRED_ROUNDED_CORNER
413     mediump float opacity = calculateCornerOpacity();
414     OUT_COLOR.a *= opacity;
415     OUT_COLOR.rgb *= mix(1.0, opacity, preMultipliedAlpha);
416 #endif
417
418 #if defined(IS_REQUIRED_DEBUG_VISUAL_SHADER) || defined(IS_REQUIRED_ROUNDED_CORNER) || defined(IS_REQUIRED_BORDERLINE)
419   }
420 #endif
421
422 #ifdef IS_REQUIRED_DEBUG_VISUAL_SHADER
423   OUT_COLOR.rgb = ApplyDebugMixColor(OUT_COLOR);
424 #endif
425 }