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;
11 #ifdef IS_REQUIRED_DEBUG_VISUAL_SHADER
12 #define DEBUG_EXTRA_VARYINGS
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;
22 #ifdef IS_REQUIRED_ALPHA_MASKING
23 uniform sampler2D sMaskTexture;
24 uniform lowp float uYFlipMaskTexture;
25 INPUT mediump vec2 vMaskTexCoord;
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;
36 #if defined(IS_REQUIRED_DEBUG_VISUAL_SHADER)
37 uniform highp vec3 uScale;
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;
50 #ifdef ATLAS_CUSTOM_WARP
51 mediump float wrapCoordinate( mediump vec2 range, mediump float coordinate, lowp float wrap )
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);
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
65 // radius of rounded corner on this quadrant
66 highp float gRadius = 0.0;
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;
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;
84 void calculateCornerRadius()
86 #ifdef IS_REQUIRED_ROUNDED_CORNER
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
96 void calculatePosition()
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;
103 gDiff = gFragmentPosition - gCenterPosition;
106 void calculatePotential()
108 gPotential = length(max(gDiff, 0.0)) + min(0.0, max(gDiff.x, gDiff.y));
111 void setupMinMaxPotential()
113 gPotentialRange = vAliasMargin;
115 gMaxOutlinePotential = gRadius + gPotentialRange;
116 gMinOutlinePotential = gRadius - gPotentialRange;
118 #ifdef IS_REQUIRED_BORDERLINE
119 gMaxInlinePotential = gMaxOutlinePotential - borderlineWidth;
120 gMinInlinePotential = gMinOutlinePotential - borderlineWidth;
122 gMaxInlinePotential = gMaxOutlinePotential;
123 gMinInlinePotential = gMinOutlinePotential;
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);
131 void PreprocessPotential()
133 calculateCornerRadius();
135 calculatePotential();
137 setupMinMaxPotential();
141 #ifdef IS_REQUIRED_BORDERLINE
142 lowp vec4 convertBorderlineColor(lowp vec4 textureColor)
144 highp float potential = gPotential;
146 // default opacity of borderline is 0.0
147 mediump float borderlineOpacity = 0.0;
149 // calculate borderline opacity by potential
150 if(potential > gMinInlinePotential)
152 // potential is inside borderline range.
153 borderlineOpacity = smoothstep(gMinInlinePotential, gMaxInlinePotential, potential);
155 // Muliply borderlineWidth to resolve very thin borderline
156 borderlineOpacity *= min(1.0, borderlineWidth / gPotentialRange);
159 lowp vec3 borderlineColorRGB = borderlineColor.rgb * uActorColor.rgb;
160 lowp float borderlineColorAlpha = borderlineColor.a * uActorColor.a;
161 borderlineColorRGB *= mix(1.0, borderlineColorAlpha, preMultipliedAlpha);
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)
168 highp float tCornerRadius = -gCenterPosition + gPotentialRange;
169 highp float MaxTexturelinePotential = tCornerRadius + gPotentialRange;
170 highp float MinTexturelinePotential = tCornerRadius - gPotentialRange;
171 if(potential > MaxTexturelinePotential)
173 // potential is out of texture range.
174 textureColor = vec4(0.0);
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);
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.
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)
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);
200 return mix(textureColor, vec4(borderlineColorRGB, borderlineColorAlpha), borderlineOpacity);
204 #ifdef IS_REQUIRED_ROUNDED_CORNER
205 mediump float calculateCornerOpacity()
207 highp float potential = gPotential;
209 // default opacity is 1.0
210 mediump float opacity = 1.0;
212 // calculate borderline opacity by potential
213 if(potential > gMaxOutlinePotential)
215 // potential is out of borderline range. just discard here
218 else if(potential > gMinOutlinePotential)
220 opacity = 1.0 - smoothstep(gMinOutlinePotential, gMaxOutlinePotential, potential);
226 #if defined(IS_REQUIRED_YUV_TO_RGB) || defined(IS_REQUIRED_UNIFIED_YUV_AND_RGB)
227 lowp vec4 ConvertYuvToRgba(mediump vec2 texCoord)
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))
234 return texture(sTexture, texCoord);
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;
242 rgba.r = y + (1.403 * v);
243 rgba.g = y - (0.344 * u) - (0.714 * v);
244 rgba.b = y + (1.770 * u);
250 #ifdef IS_REQUIRED_DEBUG_VISUAL_SHADER
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;
259 const bool IS_REQUIRED_ROUNDED_CORNER_BOOL = false;
261 #ifdef IS_REQUIRED_BORDERLINE
262 const bool IS_REQUIRED_BORDERLINE_BOOL = true;
264 const bool IS_REQUIRED_BORDERLINE_BOOL = false;
266 #ifdef IS_REQUIRED_YUV_TO_RGB
267 const bool IS_REQUIRED_YUV_TO_RGB_BOOL = true;
269 const bool IS_REQUIRED_YUV_TO_RGB_BOOL = false;
271 #ifdef IS_REQUIRED_UNIFIED_YUV_AND_RGB
272 const bool IS_REQUIRED_UNIFIED_YUV_AND_RGB_BOOL = true;
274 const bool IS_REQUIRED_UNIFIED_YUV_AND_RGB_BOOL = false;
276 #ifdef IS_REQUIRED_ALPHA_MASKING
277 const bool IS_REQUIRED_ALPHA_MASKING_BOOL = true;
279 const bool IS_REQUIRED_ALPHA_MASKING_BOOL = false;
281 #ifdef ATLAS_DEFAULT_WARP
282 const bool ATLAS_DEFAULT_WARP_BOOL = true;
284 const bool ATLAS_DEFAULT_WARP_BOOL = false;
286 #ifdef ATLAS_CUSTOM_WARP
287 const bool ATLAS_CUSTOM_WARP_BOOL = true;
289 const bool ATLAS_CUSTOM_WARP_BOOL = false;
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
308 const mediump float gMinDebugColorRate = MINIMUM_DEBUG_COLOR_RATE;
309 const mediump float gMaxDebugColorRate = MAXIMUM_DEBUG_COLOR_RATE;
311 bool DebugTriggerRed(mediump vec4 originColor)
313 DEBUG_TRIGGER_RED_CODE
316 bool DebugTriggerGreen(mediump vec4 originColor)
318 DEBUG_TRIGGER_GREEN_CODE
321 bool DebugTriggerBlue(mediump vec4 originColor)
323 DEBUG_TRIGGER_BLUE_CODE
326 mediump float DebugRatioRed(mediump vec4 originColor)
331 mediump float DebugRatioGreen(mediump vec4 originColor)
333 DEBUG_RATIO_GREEN_CODE
336 mediump float DebugRatioBlue(mediump vec4 originColor)
338 DEBUG_RATIO_BLUE_CODE
341 mediump vec3 ApplyDebugMixColor(mediump vec4 originColor)
343 mediump float debugColorRateRed = 0.0;
344 mediump float debugColorRateGreen = 0.0;
345 mediump float debugColorRateBlue = 0.0;
347 if(DebugTriggerRed(originColor))
349 debugColorRateRed = mix(gMinDebugColorRate, gMaxDebugColorRate, smoothstep(0.0, 1.0, DebugRatioRed(originColor)));
351 if(DebugTriggerGreen(originColor))
353 debugColorRateGreen = mix(gMinDebugColorRate, gMaxDebugColorRate, smoothstep(0.0, 1.0, DebugRatioGreen(originColor)));
355 if(DebugTriggerBlue(originColor))
357 debugColorRateBlue = mix(gMinDebugColorRate, gMaxDebugColorRate, smoothstep(0.0, 1.0, DebugRatioBlue(originColor)));
360 mediump float colorRate = max(debugColorRateRed, max(debugColorRateGreen, debugColorRateBlue));
361 mediump vec3 debugColor = vec3(debugColorRateRed, debugColorRateGreen, debugColorRateBlue);
363 debugColor *= mix(1.0, originColor.a, preMultipliedAlpha);
365 return originColor.rgb * (1.0 - colorRate) + debugColor;
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 ) );
377 mediump vec2 texCoord = vTexCoord;
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;
383 lowp vec4 textureColor = TEXTURE( sTexture, texCoord ) * vec4( mixColor, 1.0 ) * uColor;
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);
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)
399 OUT_COLOR = textureColor;
404 PreprocessPotential();
407 #ifdef IS_REQUIRED_BORDERLINE
408 textureColor = convertBorderlineColor(textureColor);
410 OUT_COLOR = textureColor;
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);
418 #if defined(IS_REQUIRED_DEBUG_VISUAL_SHADER) || defined(IS_REQUIRED_ROUNDED_CORNER) || defined(IS_REQUIRED_BORDERLINE)
422 #ifdef IS_REQUIRED_DEBUG_VISUAL_SHADER
423 OUT_COLOR.rgb = ApplyDebugMixColor(OUT_COLOR);