#include "clip.frag.glsl"
#include "rect.frag.glsl"
-struct ColorStop {
- float offset;
- vec4 color;
-};
-
layout(location = 0) in vec2 inPos;
layout(location = 1) in flat Rect inRect;
layout(location = 2) in float inGradientPos;
layout(location = 0) out vec4 color;
-ColorStop
-get_stop(int i)
+float
+get_offset (int i)
+{
+ return get_float (inStopOffset + i * 5);
+}
+
+vec4
+get_color (int i)
+{
+ i = clamp (i, 0, inStopCount - 1);
+ return color = vec4 (get_float (inStopOffset + i * 5 + 1),
+ get_float (inStopOffset + i * 5 + 2),
+ get_float (inStopOffset + i * 5 + 3),
+ get_float (inStopOffset + i * 5 + 4));
+}
+
+vec4
+get_color_for_range_unscaled (float start,
+ float end)
{
- ColorStop result;
+ vec4 result = vec4 (0);
+ float offset;
+ int i;
+
+ for (i = 0; i < inStopCount; i++)
+ {
+ offset = get_offset (i);
+ if (offset >= start)
+ break;
+ }
+ if (i == inStopCount)
+ offset = 1;
+
+ float last_offset = i > 0 ? get_offset (i - 1) : 0;
+ vec4 last_color = get_color (i - 1);
+ vec4 color = get_color (i);
+ if (last_offset < start)
+ {
+ last_color = mix (last_color, color, (start - last_offset) / (offset - last_offset));
+ last_offset = start;
+ }
+ if (end <= start)
+ return last_color;
- result.offset = get_float(inStopOffset + i * 5);
- result.color = vec4(get_float(inStopOffset + i * 5 + 1),
- get_float(inStopOffset + i * 5 + 2),
- get_float(inStopOffset + i * 5 + 3),
- get_float(inStopOffset + i * 5 + 4));
+ for (; i < inStopCount; i++)
+ {
+ offset = get_offset (i);
+ color = get_color (i);
+ if (offset >= end)
+ break;
+ result += 0.5 * (color + last_color) * (offset - last_offset);
+ last_offset = offset;
+ last_color = color;
+ }
+ if (i == inStopCount)
+ {
+ offset = 1;
+ color = get_color (i);
+ }
+ if (offset > end)
+ {
+ color = mix (last_color, color, (end - last_offset) / (offset - last_offset));
+ offset = end;
+ }
+ result += 0.5 * (color + last_color) * (offset - last_offset);
return result;
}
+vec4
+get_color_for_range (float start,
+ float end)
+{
+ return get_color_for_range_unscaled (start, end) / (end - start);
+}
+
void main()
{
- float pos;
+ vec4 c;
+ float pos_start, pos_end;
+ float dPos = 0.5 * abs (fwidth (inGradientPos));
if (inRepeating != 0)
- pos = fract (inGradientPos);
- else
- pos = clamp (inGradientPos, 0, 1);
-
- ColorStop stop = get_stop (0);
- float last_offset = stop.offset;
- color = stop.color;
- for (int i = 1; i < inStopCount; i++)
{
- stop = get_stop(i);
- if (stop.offset < pos)
- color = stop.color;
+ pos_start = inGradientPos - dPos;
+ pos_end = inGradientPos + dPos;
+ if (floor (pos_end) > floor (pos_start))
+ {
+ float fract_end = fract(pos_end);
+ float fract_start = fract(pos_start);
+ float n = floor (pos_end) - floor (pos_start);
+ if (fract_end > fract_start + 0.01)
+ c = get_color_for_range_unscaled (fract_start, fract_end);
+ else if (fract_start > fract_end + 0.01)
+ c = -get_color_for_range_unscaled (fract_end, fract_start);
+ c += get_color_for_range_unscaled (0.0, 1.0) * n;
+ c /= pos_end - pos_start;
+ }
else
- color = mix (color, stop.color, clamp((pos - last_offset) / (stop.offset - last_offset), 0, 1));
- last_offset = stop.offset;
- if (last_offset >= pos)
- break;
+ {
+ c = get_color_for_range (fract (pos_start), fract (pos_end));
+ }
+ }
+ else
+ {
+ pos_start = clamp (inGradientPos - dPos, 0, 1);
+ pos_end = clamp (inGradientPos + dPos, 0, 1);
+ c = get_color_for_range (pos_start, pos_end);
}
-
- if (last_offset < pos)
- color = mix (color, stop.color, clamp((pos - last_offset) / (1 - last_offset), 0, 1));
- float alpha = color.a * rect_coverage (inRect, inPos);
- color = clip_scaled (inPos, vec4(color.rgb, 1) * alpha);
+ float alpha = c.a * rect_coverage (inRect, inPos);
+ color = clip_scaled (inPos, vec4(c.rgb, 1) * alpha);
}