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 if(potential > MaxTexturelinePotential)
133 // potential is out of texture range. use borderline color instead of texture
134 textureColor = vec4(borderlineColor.xyz, 0.0);
136 else if(potential > MinTexturelinePotential)
138 // potential is in texture range
139 textureColor = mix(textureColor, vec4(borderlineColor.xyz, 0.0), smoothstep(MinTexturelinePotential, MaxTexturelinePotential, potential));
141 borderlineOpacity *= borderlineColor.a;
142 return mix(textureColor, vec4(borderlineColor.xyz, 1.0), borderlineOpacity);
144 return mix(textureColor, borderlineColor, borderlineOpacity);
148 #if IS_REQUIRED_ROUNDED_CORNER
149 mediump float calculateCornerOpacity()
151 mediump float potential = gPotential;
153 // default opacity is 1.0
154 mediump float opacity = 1.0;
156 // calculate borderline opacity by potential
157 if(potential > gMaxOutlinePotential)
159 // potential is out of borderline range. just discard here
162 else if(potential > gMinOutlinePotential)
164 opacity = 1.0 - smoothstep(gMinOutlinePotential, gMaxOutlinePotential, potential);
173 lowp vec4 textureColor = TEXTURE(sTexture, vec2(length(vTexCoord), 0.5)) * vec4(mixColor, 1.0);
175 lowp vec4 textureColor = TEXTURE(sTexture, vec2(vTexCoord.y, 0.5)) * vec4(mixColor, 1.0);
178 #if IS_REQUIRED_ROUNDED_CORNER || IS_REQUIRED_BORDERLINE
179 // skip most potential calculate for performance
180 if(abs(vPosition.x) < vOptRectSize.x && abs(vPosition.y) < vOptRectSize.y)
182 OUT_COLOR = textureColor * uColor;
185 PreprocessPotential();
188 #if IS_REQUIRED_BORDERLINE
189 textureColor = convertBorderlineColor(textureColor);
191 OUT_COLOR = textureColor * uColor;
193 #if IS_REQUIRED_ROUNDED_CORNER
194 mediump float opacity = calculateCornerOpacity();
195 OUT_COLOR *= opacity;