1 #ifndef IS_REQUIRED_ROUNDED_CORNER
2 #define IS_REQUIRED_ROUNDED_CORNER 0
4 #ifndef IS_REQUIRED_BORDERLINE
5 #define IS_REQUIRED_BORDERLINE 0
11 INPUT mediump vec2 vTexCoord;
12 #if IS_REQUIRED_ROUNDED_CORNER || IS_REQUIRED_BORDERLINE
13 INPUT mediump vec2 vPosition;
14 INPUT mediump vec2 vRectSize;
15 INPUT mediump vec2 vOptRectSize;
16 #if IS_REQUIRED_ROUNDED_CORNER
17 INPUT mediump vec4 vCornerRadius;
21 uniform sampler2D sTexture; // sampler1D?
22 uniform lowp vec4 uColor;
23 uniform lowp vec3 mixColor;
24 #if IS_REQUIRED_BORDERLINE
25 uniform mediump float borderlineWidth;
26 uniform mediump float borderlineOffset;
27 uniform lowp vec4 borderlineColor;
30 #if IS_REQUIRED_ROUNDED_CORNER || IS_REQUIRED_BORDERLINE
31 // Global values both rounded corner and borderline use
33 // radius of rounded corner on this quadrant
34 mediump float gRadius = 0.0;
36 // fragment coordinate. NOTE : vec2(0.0, 0.0) is vRectSize, the corner of visual
37 mediump vec2 gFragmentPosition = vec2(0.0, 0.0);
38 // center coordinate of rounded corner circle. vec2(gCenterPosition, gCenterPosition).
39 mediump float gCenterPosition = 0.0;
40 // relative coordinate of gFragmentPosition from gCenterPosition.
41 mediump vec2 gDiff = vec2(0.0, 0.0);
42 // potential value what our algorithm use.
43 mediump float gPotential = 0.0;
45 // threshold of potential
46 mediump float gPotentialRange = 0.0;
47 mediump float gMaxOutlinePotential = 0.0;
48 mediump float gMinOutlinePotential = 0.0;
49 mediump float gMaxInlinePotential = 0.0;
50 mediump float gMinInlinePotential = 0.0;
52 void calculateCornerRadius()
54 #if IS_REQUIRED_ROUNDED_CORNER
57 mix(vCornerRadius.x, vCornerRadius.y, sign(vPosition.x) * 0.5 + 0.5),
58 mix(vCornerRadius.w, vCornerRadius.z, sign(vPosition.x) * 0.5 + 0.5),
59 sign(vPosition.y) * 0.5 + 0.5
64 void calculatePosition()
66 gFragmentPosition = abs(vPosition) - vRectSize;
67 gCenterPosition = -gRadius;
68 #if IS_REQUIRED_BORDERLINE
69 gCenterPosition += borderlineWidth * (clamp(borderlineOffset, -1.0, 1.0) + 1.0) * 0.5;
71 gDiff = gFragmentPosition - gCenterPosition;
74 void calculatePotential()
76 gPotential = length(max(gDiff, 0.0)) + min(0.0, max(gDiff.x, gDiff.y));
79 void setupMinMaxPotential()
81 gPotentialRange = 1.0;
83 gMaxOutlinePotential = gRadius + gPotentialRange;
84 gMinOutlinePotential = gRadius - gPotentialRange;
86 #if IS_REQUIRED_BORDERLINE
87 gMaxInlinePotential = gMaxOutlinePotential - borderlineWidth;
88 gMinInlinePotential = gMinOutlinePotential - borderlineWidth;
90 gMaxInlinePotential = gMaxOutlinePotential;
91 gMinInlinePotential = gMinOutlinePotential;
94 // reduce defect near edge of rounded corner.
95 gMaxOutlinePotential += clamp(-min(gDiff.x, gDiff.y)/ max(1.0, gRadius) , 0.0, 1.0);
96 gMinOutlinePotential += clamp(-min(gDiff.x, gDiff.y)/ max(1.0, gRadius) , 0.0, 1.0);
99 void PreprocessPotential()
101 calculateCornerRadius();
103 calculatePotential();
105 setupMinMaxPotential();
110 #if IS_REQUIRED_BORDERLINE
111 lowp vec4 convertBorderlineColor(lowp vec4 textureColor)
113 mediump float potential = gPotential;
115 // default opacity of borderline is 0.0
116 mediump float borderlineOpacity = 0.0;
118 // calculate borderline opacity by potential
119 if(potential > gMinInlinePotential)
121 // potential is inside borderline range.
122 borderlineOpacity = smoothstep(gMinInlinePotential, gMaxInlinePotential, potential);
125 //calculate inside of borderline when outilneColor.a < 1.0
126 if(borderlineColor.a < 1.0)
128 mediump float tCornerRadius = -gCenterPosition;
129 mediump float MaxTexturelinePotential = tCornerRadius + gPotentialRange;
130 mediump float MinTexturelinePotential = tCornerRadius - gPotentialRange;
131 lowp vec3 BorderlineColorRGB = borderlineColor.xyz * borderlineColor.a;
132 if(potential > MaxTexturelinePotential)
134 // potential is out of texture range. use borderline color instead of texture
135 textureColor = vec4(BorderlineColorRGB, 0.0);
137 else if(potential > MinTexturelinePotential)
139 // potential is in texture range
140 textureColor = mix(textureColor, vec4(BorderlineColorRGB, 0.0), smoothstep(MinTexturelinePotential, MaxTexturelinePotential, potential));
142 borderlineOpacity *= borderlineColor.a;
143 return mix(textureColor, vec4(BorderlineColorRGB, 1.0), borderlineOpacity);
145 return mix(textureColor, borderlineColor, borderlineOpacity);
149 #if IS_REQUIRED_ROUNDED_CORNER
150 mediump float calculateCornerOpacity()
152 mediump float potential = gPotential;
154 // default opacity is 1.0
155 mediump float opacity = 1.0;
157 // calculate borderline opacity by potential
158 if(potential > gMaxOutlinePotential)
160 // potential is out of borderline range. just discard here
163 else if(potential > gMinOutlinePotential)
165 opacity = 1.0 - smoothstep(gMinOutlinePotential, gMaxOutlinePotential, potential);
174 lowp vec4 textureColor = TEXTURE(sTexture, vec2(length(vTexCoord), 0.5)) * vec4(mixColor, 1.0);
176 lowp vec4 textureColor = TEXTURE(sTexture, vec2(vTexCoord.y, 0.5)) * vec4(mixColor, 1.0);
179 #if IS_REQUIRED_ROUNDED_CORNER || IS_REQUIRED_BORDERLINE
180 // skip most potential calculate for performance
181 if(abs(vPosition.x) < vOptRectSize.x && abs(vPosition.y) < vOptRectSize.y)
183 OUT_COLOR = textureColor * uColor;
186 PreprocessPotential();
189 #if IS_REQUIRED_BORDERLINE
190 textureColor = convertBorderlineColor(textureColor);
192 OUT_COLOR = textureColor * uColor;
194 #if IS_REQUIRED_ROUNDED_CORNER
195 mediump float opacity = calculateCornerOpacity();
196 OUT_COLOR *= opacity;