1 #if defined(IS_REQUIRED_ROUNDED_CORNER) || defined(IS_REQUIRED_BORDERLINE) || defined(IS_REQUIRED_BLUR)
2 INPUT mediump vec2 vPosition;
3 INPUT mediump vec2 vRectSize;
4 INPUT mediump vec2 vOptRectSize;
5 #ifdef IS_REQUIRED_ROUNDED_CORNER
6 INPUT mediump vec4 vCornerRadius;
10 #if defined(IS_REQUIRED_ROUNDED_CORNER) || defined(IS_REQUIRED_BORDERLINE) || defined(IS_REQUIRED_BLUR)
11 // Be used when we calculate anti-alias range near 1 pixel.
12 uniform highp vec3 uScale;
15 uniform lowp vec4 uColor;
16 uniform lowp vec3 mixColor;
17 #ifdef IS_REQUIRED_BLUR
18 uniform mediump float blurRadius;
19 #elif defined(IS_REQUIRED_BORDERLINE)
20 uniform mediump float borderlineWidth;
21 uniform mediump float borderlineOffset;
22 uniform lowp vec4 borderlineColor;
23 uniform lowp vec4 uActorColor;
26 #if defined(IS_REQUIRED_ROUNDED_CORNER) || defined(IS_REQUIRED_BORDERLINE) || defined(IS_REQUIRED_BLUR)
27 // Global values both rounded corner and borderline use
29 // radius of rounded corner on this quadrant
30 mediump float gRadius = 0.0;
32 // fragment coordinate. NOTE : vec2(0.0, 0.0) is vRectSize, the corner of visual
33 mediump vec2 gFragmentPosition = vec2(0.0, 0.0);
34 // center coordinate of rounded corner circle. vec2(gCenterPosition, gCenterPosition).
35 mediump float gCenterPosition = 0.0;
36 // relative coordinate of gFragmentPosition from gCenterPosition.
37 mediump vec2 gDiff = vec2(0.0, 0.0);
38 // potential value what our algorithm use.
39 mediump float gPotential = 0.0;
41 // threshold of potential
42 mediump float gPotentialRange = 0.0;
43 mediump float gMaxOutlinePotential = 0.0;
44 mediump float gMinOutlinePotential = 0.0;
45 mediump float gMaxInlinePotential = 0.0;
46 mediump float gMinInlinePotential = 0.0;
48 void calculateCornerRadius()
50 #ifdef IS_REQUIRED_ROUNDED_CORNER
53 mix(vCornerRadius.x, vCornerRadius.y, sign(vPosition.x) * 0.5 + 0.5),
54 mix(vCornerRadius.w, vCornerRadius.z, sign(vPosition.x) * 0.5 + 0.5),
55 sign(vPosition.y) * 0.5 + 0.5
60 void calculatePosition()
62 gFragmentPosition = abs(vPosition) - vRectSize;
63 gCenterPosition = -gRadius;
64 #ifdef IS_REQUIRED_BLUR
65 #elif defined(IS_REQUIRED_BORDERLINE)
66 gCenterPosition += borderlineWidth * (clamp(borderlineOffset, -1.0, 1.0) + 1.0) * 0.5;
68 gDiff = gFragmentPosition - gCenterPosition;
71 void calculatePotential()
73 gPotential = length(max(gDiff, 0.0)) + min(0.0, max(gDiff.x, gDiff.y));
76 void setupMinMaxPotential()
78 // Set soft anti-alias range at most 10% of visual size.
79 // The range should be inverse proportion with scale of view.
80 // To avoid divid-by-zero, let we allow minimum scale value is 0.001 (0.1%)
81 gPotentialRange = min(1.0, max(vRectSize.x, vRectSize.y) * 0.2) / max(0.001, max(uScale.x, uScale.y));
83 gMaxOutlinePotential = gRadius + gPotentialRange;
84 gMinOutlinePotential = gRadius - gPotentialRange;
86 #ifdef IS_REQUIRED_BLUR
87 gMaxInlinePotential = gMaxOutlinePotential;
88 gMinInlinePotential = gMinOutlinePotential;
89 #elif defined(IS_REQUIRED_BORDERLINE)
90 gMaxInlinePotential = gMaxOutlinePotential - borderlineWidth;
91 gMinInlinePotential = gMinOutlinePotential - borderlineWidth;
93 gMaxInlinePotential = gMaxOutlinePotential;
94 gMinInlinePotential = gMinOutlinePotential;
97 // reduce defect near edge of rounded corner.
98 gMaxOutlinePotential += clamp(-min(gDiff.x, gDiff.y) / max(1.0, gRadius), 0.0, 1.0);
99 gMinOutlinePotential += clamp(-min(gDiff.x, gDiff.y) / max(1.0, gRadius), 0.0, 1.0);
102 void PreprocessPotential()
104 calculateCornerRadius();
106 calculatePotential();
108 setupMinMaxPotential();
112 #ifdef IS_REQUIRED_BLUR
113 #elif defined(IS_REQUIRED_BORDERLINE)
114 lowp vec4 convertBorderlineColor(lowp vec4 textureColor)
116 mediump float potential = gPotential;
118 // default opacity of borderline is 0.0
119 mediump float borderlineOpacity = 0.0;
121 // calculate borderline opacity by potential
122 if(potential > gMinInlinePotential)
124 // potential is inside borderline range.
125 borderlineOpacity = smoothstep(gMinInlinePotential, gMaxInlinePotential, potential);
127 // Muliply borderlineWidth to resolve very thin borderline
128 borderlineOpacity *= min(1.0, borderlineWidth / gPotentialRange);
131 lowp vec3 borderlineColorRGB = borderlineColor.rgb * uActorColor.rgb;
132 lowp float borderlineColorAlpha = borderlineColor.a * uActorColor.a;
133 // NOTE : color-visual is always not preMultiplied.
135 // Calculate inside of borderline when alpha is between (0.0 1.0). So we need to apply texture color.
136 // If borderlineOpacity is exactly 0.0, we always use whole texture color. In this case, we don't need to run below code.
137 // But if borderlineOpacity > 0.0 and borderlineColor.a == 0.0, we need to apply tCornerRadius.
138 if(borderlineOpacity > 0.0 && borderlineColor.a * borderlineOpacity < 1.0)
140 mediump float tCornerRadius = -gCenterPosition + gPotentialRange;
141 mediump float MaxTexturelinePotential = tCornerRadius + gPotentialRange;
142 mediump float MinTexturelinePotential = tCornerRadius - gPotentialRange;
143 if(potential > MaxTexturelinePotential)
145 // potential is out of texture range.
146 textureColor = vec4(0.0);
150 // potential is in texture range.
151 lowp float textureAlphaScale = mix(1.0, 0.0, smoothstep(MinTexturelinePotential, MaxTexturelinePotential, potential));
152 textureColor.a *= textureAlphaScale;
153 textureColor.rgb *= textureColor.a;
156 // NOTE : color-visual is always not preMultiplied.
157 borderlineColorAlpha *= borderlineOpacity;
158 borderlineColorRGB *= borderlineColorAlpha;
159 // We use pre-multiplied color to reduce operations.
160 // In here, textureColor and borderlineColorRGB is pre-multiplied color now.
162 // Manual blend operation with premultiplied colors.
163 // Final alpha = borderlineColorAlpha + (1.0 - borderlineColorAlpha) * textureColor.a.
164 // (Final rgb * alpha) = borderlineColorRGB + (1.0 - borderlineColorAlpha) * textureColor.rgb
165 // If preMultipliedAlpha == 1.0, just return vec4(rgb*alpha, alpha)
166 // Else, return vec4((rgb*alpha) / alpha, alpha)
168 lowp float finalAlpha = mix(textureColor.a, 1.0, borderlineColorAlpha);
169 lowp vec3 finalMultipliedRGB = borderlineColorRGB + (1.0 - borderlineColorAlpha) * textureColor.rgb;
170 // TODO : Need to find some way without division
171 return vec4(finalMultipliedRGB / finalAlpha, finalAlpha);
173 return mix(textureColor, vec4(borderlineColorRGB, borderlineColorAlpha), borderlineOpacity);
177 #ifdef IS_REQUIRED_BLUR
178 #elif defined(IS_REQUIRED_ROUNDED_CORNER)
179 mediump float calculateCornerOpacity()
181 mediump float potential = gPotential;
183 // default opacity is 1.0
184 mediump float opacity = 1.0;
186 // calculate borderline opacity by potential
187 if(potential > gMaxOutlinePotential)
189 // potential is out of borderline range. just discard here
192 else if(potential > gMinOutlinePotential)
194 opacity = 1.0 - smoothstep(gMinOutlinePotential, gMaxOutlinePotential, potential);
200 #ifdef IS_REQUIRED_BLUR
201 mediump float calculateBlurOpacity()
203 // Don't use borderline!
204 mediump vec2 v = gDiff;
205 mediump float cy = gRadius + blurRadius;
206 mediump float cr = gRadius + blurRadius;
208 #ifdef IS_REQUIRED_ROUNDED_CORNER
209 // This routine make perfect circle. If corner radius is not exist, we don't consider prefect circle.
210 cy = min(cy, min(vRectSize.x, vRectSize.y) - gRadius);
212 v = vec2(min(v.x, v.y), max(v.x, v.y));
215 mediump float potential = 0.0;
216 mediump float alias = min(gRadius, 1.0);
217 mediump float potentialMin = cy + gRadius - blurRadius - alias;
218 mediump float potentialMax = cy + gRadius + blurRadius + alias;
220 // move center of circles for reduce defact
221 mediump float cyDiff = min(cy, 0.2 * blurRadius);
225 mediump float diffFromBaseline = cy * v.y - (cy + cr) * v.x;
227 if(diffFromBaseline > 0.0)
229 // out of calculation bound.
232 // for anti-alias when blurRaidus = 0.0
233 mediump float heuristicBaselineScale = max(1.0 , cr * (cr + cy));
234 mediump float potentialDiff = min(alias, diffFromBaseline / heuristicBaselineScale);
235 potentialMin += potentialDiff;
236 potentialMax -= potentialDiff;
240 // get some circle centered (x, x) and radius (r = cr / cy * x)
241 // s.t. point v is on that circle
242 // highest point of that circle is (x, x + r) and potential is x + r
244 // solve (v.x - x)^2 + (v.y - x)^2 = (cr / cy * x)^2
245 #ifdef IS_REQUIRED_ROUNDED_CORNER
246 // Note : lowspec HW cannot calculate here. need to reduce numeric error
247 highp float A = (cr * cr - 2.0 * cy * cy);
248 highp float B = cy * (v.x + v.y);
249 highp float V = dot(v,v);
250 highp float D = B * B + A * V;
251 potential = V * (cr + cy) / (sqrt(D) + B);
253 // We can simplify this value cause cy = 0.8 * blurRadius, cr = 1.2 * blurRadius
254 // potential = 5.0*(sqrt(4.0*(v.x+v.y)^2 + dot(v,v)) - 2.0*(v.x+v.y));
255 // = 10.0*(v.x+v.y) * (sqrt(1.0 + (length(v) / (2.0*(v.x+v.y)))^2) - 1.0);
256 // = 10.0*(v.x+v.y) * (sqrt(1.25 - x + x^2) - 1.0);
257 // ~= 10.0*(v.x+v.y) * (0.11803399 - 0.44721360x + 0.35777088x^2 - 0.14310x^3 + O(x^5)) (Taylor series)
258 // ~= -1.0557281 * (v.x + v.y) + 2.236068 * length(v) - ~~~ (here, x <= 0.5 * (1.0 - sqrt(0.5)) < 0.1464467)
259 // Note : This simplify need cause we should use it on lowspec HW.
260 mediump float x = 0.5 * (1.0 - length(v) / (v.x + v.y));
261 potential = -1.0557281 * (v.x + v.y) + 2.236068 * length(v) + 10.0 * (v.x + v.y) * (0.35777088 - 0.14310 * x) * x * x;
265 return 1.0 - smoothstep(potentialMin, potentialMax, potential);
271 lowp vec4 targetColor = vec4(mixColor, 1.0) * uColor;
273 #if defined(IS_REQUIRED_BLUR) || defined(IS_REQUIRED_ROUNDED_CORNER) || defined(IS_REQUIRED_BORDERLINE)
274 // skip most potential calculate for performance
275 if(abs(vPosition.x) < vOptRectSize.x && abs(vPosition.y) < vOptRectSize.y)
277 OUT_COLOR = targetColor;
281 PreprocessPotential();
284 #ifdef IS_REQUIRED_BLUR
285 #elif defined(IS_REQUIRED_BORDERLINE)
286 targetColor = convertBorderlineColor(targetColor);
288 OUT_COLOR = targetColor;
290 #ifdef IS_REQUIRED_BLUR
291 mediump float opacity = calculateBlurOpacity();
292 OUT_COLOR.a *= opacity;
293 #elif defined(IS_REQUIRED_ROUNDED_CORNER)
294 mediump float opacity = calculateCornerOpacity();
295 OUT_COLOR.a *= opacity;
298 #if defined(IS_REQUIRED_BLUR) || defined(IS_REQUIRED_ROUNDED_CORNER) || defined(IS_REQUIRED_BORDERLINE)